/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "MLSTransactionParent.h"

#include "MLSLogging.h"
#include "MLSTransactionMessage.h"
#include "mozilla/Base64.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/security/mls/mls_gk_ffi_generated.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsIPrincipal.h"
#include "nsString.h"

using mozilla::dom::quota::QuotaManager;

namespace mozilla::dom {

/* static */ nsresult MLSTransactionParent::CreateDirectoryIfNotExists(
    nsIFile* aDir) {
  nsresult rv = aDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
  if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
    // Evaluate if the file is a directory
    bool isDirectory = false;
    rv = aDir->IsDirectory(&isDirectory);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    // Check if the file is actually a directory
    if (!isDirectory) {
      return NS_ERROR_FILE_NOT_DIRECTORY;
    }
    return NS_OK;
  }
  return rv;
}

/* static */ nsresult MLSTransactionParent::ConstructDatabasePrefixPath(
    nsCOMPtr<nsIFile>& aFile) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ConstructDatabasePath()"));

  // Get the base path from the quota manager
  QuotaManager* quotaManager = QuotaManager::Get();
  if (NS_WARN_IF(!quotaManager)) {
    return NS_ERROR_FAILURE;
  }

  // Create an nsIFile object from the path
  nsresult rv =
      NS_NewLocalFile(quotaManager->GetBasePath(), getter_AddRefs(aFile));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  // Append the hardcoded "mls" directory name to the path
  rv = aFile->AppendNative("mls"_ns);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  return NS_OK;
}

/* static */ nsresult MLSTransactionParent::ConstructDatabaseFullPath(
    nsCOMPtr<nsIFile>& aFile, nsIPrincipal* aPrincipal,
    nsCString& aDatabasePath) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ConstructDatabaseFullPath()"));

  // Get StorageOriginKey
  nsAutoCString originKey;
  nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  // Get OriginSuffix
  nsAutoCString originAttrSuffix;
  rv = aPrincipal->GetOriginSuffix(originAttrSuffix);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  // Set the base path and origin
  nsAutoCString origin = originKey + originAttrSuffix;

  // Encode the origin with its suffix
  nsAutoCString encodedOrigin;
  rv = mozilla::Base64Encode(origin, encodedOrigin);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ConstructDatabasePath() - origin: %s",
           origin.get()));

  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ConstructDatabasePath() - encodedOrigin: "
           "%s",
           encodedOrigin.get()));

  // Append the origin to the path
  rv = aFile->AppendNative(encodedOrigin);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  // Get the updated path back into the nsCString
  nsAutoString databasePathUTF16;
  rv = aFile->GetPath(databasePathUTF16);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  aDatabasePath = NS_ConvertUTF16toUTF8(databasePathUTF16);
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ConstructDatabasePath() - databasePath: %s",
           aDatabasePath.get()));

  return NS_OK;
}

void MLSTransactionParent::ActorDestroy(ActorDestroyReason) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::ActorDestroy()"));
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestStateDelete(
    RequestStateDeleteResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestStateDelete()"));

  // Call to the MLS rust code
  nsresult rv = security::mls::mls_state_delete(&mDatabasePath);

  aResolver(NS_SUCCEEDED(rv));
  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupStateDelete(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier,
    RequestGroupStateDeleteResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupStateDelete()"));

  // Call to the MLS rust code
  security::mls::GkGroupIdEpoch groupIdEpoch;
  nsresult rv = security::mls::mls_state_delete_group(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), &groupIdEpoch);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(groupIdEpoch)));
  return IPC_OK();
}

mozilla::ipc::IPCResult
MLSTransactionParent::RecvRequestGenerateIdentityKeypair(
    RequestGenerateIdentityKeypairResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGenerateIdentityKeypair()"));

  // Call to the MLS rust code
  nsTArray<uint8_t> identity;
  nsresult rv = security::mls::mls_generate_identity(&mDatabasePath, &identity);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(identity)}));
  return IPC_OK();
}

mozilla::ipc::IPCResult
MLSTransactionParent::RecvRequestGenerateCredentialBasic(
    const nsTArray<uint8_t>& aCredContent,
    RequestGenerateCredentialBasicResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGenerateCredentialBasic()"));

  // Call to the MLS rust code
  nsTArray<uint8_t> credential;
  nsresult rv = security::mls::mls_generate_credential_basic(
      aCredContent.Elements(), aCredContent.Length(), &credential);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(credential)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGenerateKeyPackage(
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aCredential,
    RequestGenerateKeyPackageResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGenerateKeyPackage()"));

  // Call to the MLS rust code
  nsTArray<uint8_t> keyPackage;
  nsresult rv = security::mls::mls_generate_keypackage(
      &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(),
      aCredential.Elements(), aCredential.Length(), &keyPackage);

  // Return Nothing if failed
  if (NS_FAILED(rv)) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(keyPackage)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupCreate(
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aCredential,
    const nsTArray<uint8_t>& aInOptGroupIdentifier,
    RequestGroupCreateResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupCreate()"));

  // Call to the MLS rust code
  security::mls::GkGroupIdEpoch groupIdEpoch;
  nsresult rv = security::mls::mls_group_create(
      &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(),
      aCredential.Elements(), aCredential.Length(),
      aInOptGroupIdentifier.Elements(), aInOptGroupIdentifier.Length(),
      &groupIdEpoch);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(groupIdEpoch)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupJoin(
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aWelcome,
    RequestGroupJoinResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupJoin()"));

  // Call to the MLS rust code
  security::mls::GkGroupIdEpoch groupIdEpoch;
  nsresult rv = security::mls::mls_group_join(
      &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(),
      aWelcome.Elements(), aWelcome.Length(), &groupIdEpoch);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(groupIdEpoch)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupAdd(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aKeyPackage,
    RequestGroupAddResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupAdd()"));

  // Call to the MLS rust code
  security::mls::GkMlsCommitOutput commitOutput;
  nsresult rv = security::mls::mls_group_add(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aKeyPackage.Elements(),
      aKeyPackage.Length(), &commitOutput);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(commitOutput)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupProposeAdd(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aKeyPackage,
    RequestGroupProposeAddResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupProposeAdd()"));

  // Call to the MLS rust code
  nsTArray<uint8_t> proposal;
  nsresult rv = security::mls::mls_group_propose_add(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aKeyPackage.Elements(),
      aKeyPackage.Length(), &proposal);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(proposal)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupRemove(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier,
    const nsTArray<uint8_t>& aRemIdentifier,
    RequestGroupRemoveResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupRemove()"));

  // Call to the MLS rust code
  security::mls::GkMlsCommitOutput commitOutput;
  nsresult rv = security::mls::mls_group_remove(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aRemIdentifier.Elements(),
      aRemIdentifier.Length(), &commitOutput);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(commitOutput)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupProposeRemove(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier,
    const nsTArray<uint8_t>& aRemIdentifier,
    RequestGroupProposeRemoveResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupProposeRemove()"));

  nsTArray<uint8_t> proposal;
  nsresult rv = security::mls::mls_group_propose_remove(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aRemIdentifier.Elements(),
      aRemIdentifier.Length(), &proposal);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(proposal)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupClose(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier,
    RequestGroupCloseResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupClose()"));

  // Call to the MLS rust code
  security::mls::GkMlsCommitOutput commitOutput;
  nsresult rv = security::mls::mls_group_close(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), &commitOutput);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(commitOutput)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupDetails(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier,
    RequestGroupDetailsResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGroupDetails()"));

  // Call to the MLS rust code
  security::mls::GkGroupDetails details;
  nsresult rv = security::mls::mls_group_details(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), &details);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(details)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestSend(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aMessage,
    RequestSendResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestSend()"));

  // Call to the MLS rust code
  nsTArray<uint8_t> outputMessage;
  nsresult rv = security::mls::mls_send(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aMessage.Elements(),
      aMessage.Length(), &outputMessage);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(outputMessage)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestReceive(
    const nsTArray<uint8_t>& aClientIdentifier,
    const nsTArray<uint8_t>& aMessage, RequestReceiveResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestReceive()"));

  // Call to the MLS rust code
  GkReceived received;
  nsTArray<uint8_t> group_id_bytes;

  nsresult rv = security::mls::mls_receive(
      &mDatabasePath, aClientIdentifier.Elements(), aClientIdentifier.Length(),
      aMessage.Elements(), aMessage.Length(), &group_id_bytes, &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(GkReceived());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingProposals(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aClientIdentifier,
    RequestHasPendingProposalsResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestHasPendingProposals()"));

  // Call to the MLS rust code
  bool received = true;
  nsresult rv = security::mls::mls_has_pending_proposals(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(received);
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingProposals(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aClientIdentifier,
    RequestClearPendingProposalsResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestCleanPendingProposals()"));

  // Call to the MLS rust code
  bool received = true;
  nsresult rv = security::mls::mls_clear_pending_proposals(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(received);
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingCommit(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aClientIdentifier,
    RequestHasPendingCommitResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestHasPendingCommit()"));

  // Call to the MLS rust code
  bool received = true;
  nsresult rv = security::mls::mls_has_pending_commit(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(received);
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingCommit(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aClientIdentifier,
    RequestClearPendingCommitResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestCleanPendingCommit()"));

  // Call to the MLS rust code
  bool received = true;
  nsresult rv = security::mls::mls_clear_pending_commit(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(received);
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestApplyPendingCommit(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aClientIdentifier,
    RequestApplyPendingCommitResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestApplyPendingCommit()"));

  // Call to the MLS rust code
  GkReceived received;
  nsresult rv = security::mls::mls_apply_pending_commit(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(GkReceived());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(received);

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestExportSecret(
    const nsTArray<uint8_t>& aGroupIdentifier,
    const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aLabel,
    const nsTArray<uint8_t>& aContext, uint64_t aLen,
    RequestExportSecretResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestExportSecret()"));

  // Call to the MLS rust code
  security::mls::GkExporterOutput exporterOutput;
  nsresult rv = security::mls::mls_derive_exporter(
      &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
      aIdentifier.Elements(), aIdentifier.Length(), aLabel.Elements(),
      aLabel.Length(), aContext.Elements(), aContext.Length(), aLen,
      &exporterOutput);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(std::move(exporterOutput)));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupIdentifier(
    const nsTArray<uint8_t>& aMessage,
    RequestGetGroupIdentifierResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGetGroupIdentifier()"));

  nsTArray<uint8_t> groupId;
  nsresult rv = security::mls::mls_get_group_id(aMessage.Elements(),
                                                aMessage.Length(), &groupId);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(groupId)}));

  return IPC_OK();
}

mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupEpoch(
    const nsTArray<uint8_t>& aMessage,
    RequestGetGroupIdentifierResolver&& aResolver) {
  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
          ("MLSTransactionParent::RecvRequestGetGroupEpoch()"));

  nsTArray<uint8_t> groupEpoch;
  nsresult rv = security::mls::mls_get_group_epoch(
      aMessage.Elements(), aMessage.Length(), &groupEpoch);

  // Return Nothing if failed
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aResolver(Nothing());
    return IPC_OK();
  }

  // Return the result if success
  aResolver(Some(RawBytes{std::move(groupEpoch)}));

  return IPC_OK();
}

}  // namespace mozilla::dom
