// Copyright 2019 The Fuchsia 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 <dirent.h>
#include <fcntl.h>
#include <fuchsia/boot/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/sys/cpp/testing/service_directory_provider.h>
#include <lib/zx/job.h>
#include <lib/zx/object.h>
#include <unistd.h>
#include <zircon/status.h>

#include <array>
#include <string>
#include <thread>

#include <fbl/unique_fd.h>
#include <gtest/gtest.h>

#include "src/developer/sshd-host/service.h"
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"

namespace sshd_host {

using fuchsia::boot::Items;

// Mock fuchsia.boot.Items server
class FakeItems : public Items {
 public:
  fidl::InterfaceRequestHandler<Items> GetHandler() { return bindings_.GetHandler(this); }

  void Get(uint32_t type, uint32_t extra, GetCallback callback) { EXPECT_TRUE(false); }

  void GetBootloaderFile(::std::string filename, GetBootloaderFileCallback callback) {
    if (!bootloader_file_set_) {
      callback(zx::vmo(ZX_HANDLE_INVALID));
      return;
    }
    bootloader_file_set_ = false;

    if (filename == filename_) {
      callback(std::move(vmo_));
    } else {
      callback(zx::vmo(ZX_HANDLE_INVALID));
    }
  }

  void SetFile(const char *filename, const char *payload, uint64_t payload_len) {
    filename_ = std::string(filename);

    ASSERT_EQ(zx::vmo::create(payload_len, 0, &vmo_), ZX_OK);
    ASSERT_EQ(vmo_.write((payload), 0, payload_len), ZX_OK);
    ASSERT_EQ(vmo_.set_property(ZX_PROP_VMO_CONTENT_SIZE, &payload_len, sizeof(payload_len)),
              ZX_OK);

    bootloader_file_set_ = true;
  }

 private:
  fidl::BindingSet<Items> bindings_;
  bool bootloader_file_set_ = false;
  std::string filename_;
  ::zx::vmo vmo_;
};

class SshdHostBootItemTest : public gtest::RealLoopFixture {
 public:
  void SetUp() override {
    EXPECT_EQ(loop_.StartThread(), ZX_OK);
    service_directory_provider_.reset(
        new ::sys::testing::ServiceDirectoryProvider(loop_.dispatcher()));
    fake_items_.reset(new FakeItems);
    EXPECT_EQ(service_directory_provider_->AddService(fake_items_->GetHandler()), ZX_OK);
  }

  void TearDown() override {
    loop_.Quit();
    loop_.JoinThreads();
  }

  async::Loop loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
  std::unique_ptr<::sys::testing::ServiceDirectoryProvider> service_directory_provider_;
  std::unique_ptr<FakeItems> fake_items_;
  thrd_t thread_;
};

static void remove_authorized_keys() {
  if (unlink(kAuthorizedKeysPath)) {
    ASSERT_EQ(errno, ENOENT);
  }
  if (rmdir(kSshDirectory)) {
    ASSERT_EQ(errno, ENOENT);
  }
}

static void write_authorized_keys(const char *payload, ssize_t len) {
  if (mkdir(kSshDirectory, 0700), 0) {
    ASSERT_EQ(errno, EEXIST);
  }
  fbl::unique_fd kfd(open(kAuthorizedKeysPath, O_CREAT | O_TRUNC | O_WRONLY));
  ASSERT_TRUE(kfd.is_valid());
  ASSERT_EQ(write(kfd.get(), payload, len), len);
  fsync(kfd.get());
  ASSERT_EQ(close(kfd.release()), 0);
}

static void verify_authorized_keys(const char *payload, ssize_t len) {
  auto file_buf = std::make_unique<uint8_t[]>(len);

  fbl::unique_fd kfd(open(kAuthorizedKeysPath, O_RDONLY));
  ASSERT_TRUE(kfd.is_valid());
  ASSERT_EQ(read(kfd.get(), file_buf.get(), len), len);
  // verify entire file was read.
  uint8_t tmp;
  ASSERT_EQ(read(kfd.get(), &tmp, sizeof(uint8_t)), 0);
  ASSERT_EQ(close(kfd.release()), 0);

  ASSERT_EQ(memcmp(file_buf.get(), payload, len), 0);
}

// If key file does not exist and the bootloader file is not found, nothing should happen.
TEST_F(SshdHostBootItemTest, TestNoKeyFileNoBootloaderFile) {
  remove_authorized_keys();

  zx_status_t status = provision_authorized_keys_from_bootloader_file(
      service_directory_provider_->service_directory());
  ASSERT_EQ(status, ZX_ERR_NOT_FOUND);

  ASSERT_EQ(opendir(kSshDirectory), nullptr);
  ASSERT_EQ(errno, ENOENT);
}

// If key file exists and no bootloader file is found, file should be untouched.
TEST_F(SshdHostBootItemTest, TestKeyFileExistsNoBootloaderFile) {
  constexpr char kAuthorizedKeysPayload[] = "authorized_keys_file_data";
  write_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));

  zx_status_t status = provision_authorized_keys_from_bootloader_file(
      service_directory_provider_->service_directory());
  ASSERT_EQ(status, ZX_ERR_NOT_FOUND);

  verify_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));
}

// If key file does not exist and a bootloader file is found, file should be written.
TEST_F(SshdHostBootItemTest, TestBootloaderFileProvisioningNoKeyFile) {
  constexpr char kAuthorizedKeysPayload[] = "authorized_keys_file_data_new";

  fake_items_->SetFile(kAuthorizedKeysBootloaderFileName.data(), kAuthorizedKeysPayload,
                       strlen(kAuthorizedKeysPayload));

  remove_authorized_keys();

  zx_status_t status = provision_authorized_keys_from_bootloader_file(
      service_directory_provider_->service_directory());
  ASSERT_EQ(status, ZX_OK);

  verify_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));
}

// If key file does not exist, the ssh directory does exist and a bootloader file is found,
// key file should be written.
TEST_F(SshdHostBootItemTest, TestBootloaderFileProvisioningSshDirNoKeyFile) {
  constexpr char kAuthorizedKeysPayload[] = "authorized_keys_file_data_new";

  fake_items_->SetFile(kAuthorizedKeysBootloaderFileName.data(), kAuthorizedKeysPayload,
                       strlen(kAuthorizedKeysPayload));

  remove_authorized_keys();
  ASSERT_EQ(mkdir(kSshDirectory, 0700), 0);

  zx_status_t status = provision_authorized_keys_from_bootloader_file(
      service_directory_provider_->service_directory());
  ASSERT_EQ(status, ZX_OK);

  verify_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));
}

// If key file already exists and a bootloader file is found, key file should not be changed.
TEST_F(SshdHostBootItemTest, TestBootloaderFileNotProvisionedWithExistingKeyFile) {
  constexpr char kAuthorizedKeysPayload[] = "existing authorized_keys_file_data";
  write_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));

  constexpr char kAuthorizedKeysBootItemPayload[] = "new authorized_keys_file_data";
  fake_items_->SetFile(kAuthorizedKeysBootloaderFileName.data(), kAuthorizedKeysBootItemPayload,
                       strlen(kAuthorizedKeysBootItemPayload));

  zx_status_t status = provision_authorized_keys_from_bootloader_file(
      service_directory_provider_->service_directory());
  ASSERT_EQ(status, ZX_ERR_ALREADY_EXISTS);

  verify_authorized_keys(kAuthorizedKeysPayload, strlen(kAuthorizedKeysPayload));
}

TEST(SshdHostTest, TestMakeChildJob) {
  zx_status_t s;
  zx::job parent;
  s = zx::job::create(*zx::job::default_job(), 0, &parent);
  ASSERT_EQ(s, ZX_OK);

  std::array<zx_koid_t, 10> children;
  size_t num_children;

  s = parent.get_info(ZX_INFO_JOB_CHILDREN, (void *)&children,
                      sizeof(zx_koid_t) * children.max_size(), &num_children, nullptr);
  ASSERT_EQ(s, ZX_OK);

  ASSERT_EQ(num_children, (size_t)0);

  zx::job job;
  ASSERT_EQ(sshd_host::make_child_job(parent, std::string("test job"), &job), ZX_OK);

  s = parent.get_info(ZX_INFO_JOB_CHILDREN, (void *)&children, sizeof(zx_koid_t) * children.size(),
                      &num_children, nullptr);
  ASSERT_EQ(s, ZX_OK);

  ASSERT_EQ(num_children, (size_t)1);

  zx_info_handle_basic_t info = {};

  s = job.get_info(ZX_INFO_HANDLE_BASIC, (void *)&info, sizeof(info), nullptr, nullptr);
  ASSERT_EQ(s, ZX_OK);

  ASSERT_EQ(info.rights, kChildJobRights);
}

}  // namespace sshd_host
