/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014-2023, Regents of the University of California
 *
 * NAC library is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * NAC library is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 *
 * You should have received copies of the GNU General Public License and GNU Lesser
 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * See AUTHORS.md for complete list of NAC library authors and contributors.
 */

#include "encryptor.hpp"

#include <ndn-cxx/security/transform/block-cipher.hpp>
#include <ndn-cxx/security/transform/buffer-source.hpp>
#include <ndn-cxx/security/transform/stream-sink.hpp>
#include <ndn-cxx/util/logger.hpp>
#include <ndn-cxx/util/random.hpp>

#include <boost/lexical_cast.hpp>

namespace ndn::nac {

NDN_LOG_INIT(nac.Encryptor);

constexpr size_t N_RETRIES = 3;

Encryptor::Encryptor(const Name& accessPrefix,
                     const Name& ckPrefix, SigningInfo ckDataSigningInfo,
                     const ErrorCallback& onFailure,
                     Validator&, KeyChain& keyChain, Face& face)
  : m_accessPrefix(accessPrefix)
  , m_ckPrefix(ckPrefix)
  , m_ckBits(AES_KEY_SIZE)
  , m_ckDataSigningInfo(std::move(ckDataSigningInfo))
  , m_isKekRetrievalInProgress(false)
  , m_onFailure(onFailure)
  , m_keyChain(keyChain)
  , m_face(face)
  , m_scheduler(face.getIoContext())
{
  regenerateCk();

  auto serveFromIms = [this] (const Name&, const Interest& interest) {
    auto data = m_ims.find(interest);
    if (data != nullptr) {
      NDN_LOG_DEBUG("Serving " << data->getName() << " from InMemoryStorage");
      m_face.put(*data);
    }
    else {
      NDN_LOG_DEBUG("Didn't find CK data for " << interest.getName());
      // send NACK?
    }
  };

  auto handleError = [] (const Name& prefix, const std::string& msg) {
    NDN_LOG_ERROR("Failed to register prefix " << prefix << ": " << msg);
  };

  m_ckReg = m_face.setInterestFilter(Name(ckPrefix).append(CK), serveFromIms, handleError);
}

Encryptor::~Encryptor()
{
  m_kekPendingInterest.cancel();
}

void
Encryptor::retryFetchingKek()
{
  if (m_isKekRetrievalInProgress) {
    return;
  }

  NDN_LOG_DEBUG("Retrying fetching of KEK");
  m_isKekRetrievalInProgress = true;
  fetchKekAndPublishCkData([&] {
      NDN_LOG_DEBUG("KEK retrieved and published");
      m_isKekRetrievalInProgress = false;
    },
    [=] (const ErrorCode& code, const std::string& msg) {
      NDN_LOG_ERROR("Failed to retrieved KEK: " + msg);
      m_isKekRetrievalInProgress = false;
      m_onFailure(code, msg);
    },
    N_RETRIES);
}

void
Encryptor::regenerateCk()
{
  m_ckName = m_ckPrefix;
  m_ckName
    .append(CK)
    .appendVersion(); // version = ID of CK
  NDN_LOG_DEBUG("Generating new CK: " << m_ckName);
  random::generateSecureBytes(m_ckBits);

  // one implication: if CK updated before KEK fetched, KDK for the old CK will not be published
  if (!m_kek) {
    retryFetchingKek();
  }
  else {
    makeAndPublishCkData(m_onFailure);
  }
}

EncryptedContent
Encryptor::encrypt(span<const uint8_t> data)
{
  // Generate IV
  auto iv = make_shared<Buffer>(AES_IV_SIZE);
  random::generateSecureBytes(*iv);

  OBufferStream os;
  security::transform::bufferSource(data)
    >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
                                        CipherOperator::ENCRYPT,
                                        m_ckBits, *iv)
    >> security::transform::streamSink(os);

  EncryptedContent content;
  content.setIv(iv);
  content.setPayload(os.buf());
  content.setKeyLocator(m_ckName);

  return content;
}

void
Encryptor::fetchKekAndPublishCkData(const std::function<void()>& onReady,
                                    const ErrorCallback& onFailure,
                                    size_t nTriesLeft)
{
  // interest for <access-prefix>/KEK to retrieve <access-prefix>/KEK/<key-id> KekData

  NDN_LOG_DEBUG("Fetching KEK " << Name(m_accessPrefix).append(KEK));

  auto kekInterest = Interest(Name(m_accessPrefix).append(KEK))
                     .setCanBePrefix(true)
                     .setMustBeFresh(true);
  m_kekPendingInterest = m_face.expressInterest(kekInterest,
    [=] (const Interest&, const Data& kek) {
      // @todo verify if the key is legit
      m_kek = kek;
      if (makeAndPublishCkData(onFailure)) {
        onReady();
      }
      // otherwise, failure has been already declared
    },
    [=] (const Interest& i, const lp::Nack& nack) {
      if (nTriesLeft > 1) {
        m_scheduler.schedule(RETRY_DELAY_AFTER_NACK, [=] {
          fetchKekAndPublishCkData(onReady, onFailure, nTriesLeft - 1);
        });
      }
      else {
        onFailure(ErrorCode::KekRetrievalFailure, "Retrieval of KEK [" + i.getName().toUri() +
                  "] failed. Got NACK with reason " + boost::lexical_cast<std::string>(nack.getReason()));
        NDN_LOG_DEBUG("Scheduling retry from NACK");
        m_scheduler.schedule(RETRY_DELAY_KEK_RETRIEVAL, [this] { retryFetchingKek(); });
      }
    },
    [=] (const Interest& i) {
      if (nTriesLeft > 1) {
        fetchKekAndPublishCkData(onReady, onFailure, nTriesLeft - 1);
      }
      else {
        onFailure(ErrorCode::KekRetrievalTimeout,
                  "Retrieval of KEK [" + i.getName().toUri() + "] timed out");
        NDN_LOG_DEBUG("Scheduling retry after all timeouts");
        m_scheduler.schedule(RETRY_DELAY_KEK_RETRIEVAL, [this] { retryFetchingKek(); });
      }
    });
}

bool
Encryptor::makeAndPublishCkData(const ErrorCallback& onFailure)
{
  try {
    PublicKey kek;
    kek.loadPkcs8(m_kek->getContent().value_bytes());

    EncryptedContent content;
    content.setPayload(kek.encrypt(m_ckBits));

    auto ckData = make_shared<Data>(Name(m_ckName).append(ENCRYPTED_BY).append(m_kek->getName()));
    ckData->setContent(content.wireEncode());
    // FreshnessPeriod can serve as a soft access control for revoking access
    ckData->setFreshnessPeriod(DEFAULT_CK_FRESHNESS_PERIOD);
    m_keyChain.sign(*ckData, m_ckDataSigningInfo);
    m_ims.insert(*ckData);

    NDN_LOG_DEBUG("Publishing CK data: " << ckData->getName());
    return true;
  }
  catch (const std::runtime_error&) {
    onFailure(ErrorCode::EncryptionFailure,
              "Failed to encrypt generated CK with KEK " + m_kek->getName().toUri());
    return false;
  }
}

} // namespace ndn::nac
