tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MLS.cpp (24311B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/MLS.h"
      8 
      9 #include "MLSGroupView.h"
     10 #include "MLSLogging.h"
     11 #include "MLSTypeUtils.h"
     12 #include "mozilla/BasePrincipal.h"
     13 #include "mozilla/Logging.h"
     14 #include "mozilla/dom/MLSGroupView.h"
     15 #include "mozilla/dom/MLSTransactionChild.h"
     16 #include "mozilla/dom/MLSTransactionMessage.h"
     17 #include "mozilla/dom/PMLSTransaction.h"
     18 #include "mozilla/dom/Promise.h"
     19 #include "mozilla/dom/TypedArray.h"
     20 #include "mozilla/ipc/BackgroundChild.h"
     21 #include "mozilla/ipc/Endpoint.h"
     22 #include "mozilla/ipc/PBackgroundChild.h"
     23 #include "nsCOMPtr.h"
     24 #include "nsDebug.h"
     25 #include "nsIGlobalObject.h"
     26 #include "nsTArray.h"
     27 
     28 namespace mozilla::dom {
     29 
     30 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MLS, mGlobalObject)
     31 
     32 NS_IMPL_CYCLE_COLLECTING_ADDREF(MLS)
     33 NS_IMPL_CYCLE_COLLECTING_RELEASE(MLS)
     34 
     35 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MLS)
     36  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     37  NS_INTERFACE_MAP_ENTRY(nsISupports)
     38 NS_INTERFACE_MAP_END
     39 
     40 // Setup logging
     41 mozilla::LazyLogModule gMlsLog("MLS");
     42 
     43 /* static */ already_AddRefed<MLS> MLS::Constructor(GlobalObject& aGlobalObject,
     44                                                    ErrorResult& aRv) {
     45  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::Constructor()"));
     46 
     47  nsCOMPtr<nsIGlobalObject> global(
     48      do_QueryInterface(aGlobalObject.GetAsSupports()));
     49  if (NS_WARN_IF(!global)) {
     50    aRv.Throw(NS_ERROR_FAILURE);
     51    return nullptr;
     52  }
     53 
     54  // Get the principal and perform some validation on it.
     55  // We do not allow MLS in Private Browsing Mode for now.
     56  nsIPrincipal* principal = global->PrincipalOrNull();
     57  if (!principal || !principal->GetIsContentPrincipal() ||
     58      principal->GetIsInPrivateBrowsing()) {
     59    aRv.ThrowSecurityError("Cannot create MLS store for origin");
     60    return nullptr;
     61  }
     62 
     63  // Create the endpoints for the MLS actor
     64  mozilla::ipc::Endpoint<PMLSTransactionParent> parentEndpoint;
     65  mozilla::ipc::Endpoint<PMLSTransactionChild> childEndpoint;
     66  MOZ_ALWAYS_SUCCEEDS(
     67      PMLSTransaction::CreateEndpoints(&parentEndpoint, &childEndpoint));
     68 
     69  mozilla::ipc::PBackgroundChild* backgroundChild =
     70      mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
     71  if (!backgroundChild) {
     72    aRv.Throw(NS_ERROR_UNEXPECTED);
     73    return nullptr;
     74  }
     75 
     76  // Bind the child actor, and send the parent endpoint.
     77  RefPtr<MLSTransactionChild> actor = new MLSTransactionChild();
     78  MOZ_ALWAYS_TRUE(childEndpoint.Bind(actor));
     79 
     80  MOZ_ALWAYS_TRUE(backgroundChild->SendCreateMLSTransaction(
     81      std::move(parentEndpoint), WrapNotNull(principal)));
     82 
     83  return MakeAndAddRef<MLS>(global, actor);
     84 }
     85 
     86 MLS::MLS(nsIGlobalObject* aGlobalObject, MLSTransactionChild* aActor)
     87    : mGlobalObject(aGlobalObject), mTransactionChild(aActor) {
     88  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::MLS()"));
     89 }
     90 
     91 MLS::~MLS() {
     92  if (mTransactionChild) {
     93    mTransactionChild->Close();
     94  }
     95 }
     96 
     97 JSObject* MLS::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     98  return MLS_Binding::Wrap(aCx, this, aGivenProto);
     99 }
    100 
    101 //
    102 // API
    103 //
    104 
    105 already_AddRefed<Promise> MLS::DeleteState(ErrorResult& aRv) {
    106  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::DeleteState()"));
    107 
    108  // Create a new Promise object for the result
    109  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    110  if (NS_WARN_IF(aRv.Failed())) {
    111    return nullptr;
    112  }
    113 
    114  mTransactionChild->SendRequestStateDelete(
    115      [promise](bool result) {
    116        if (result) {
    117          promise->MaybeResolveWithUndefined();
    118        } else {
    119          promise->MaybeReject(NS_ERROR_FAILURE);
    120        }
    121      },
    122      [promise](::mozilla::ipc::ResponseRejectReason) {
    123        promise->MaybeRejectWithUnknownError("deleteState failed");
    124      });
    125 
    126  return promise.forget();
    127 }
    128 
    129 already_AddRefed<Promise> MLS::GenerateIdentity(ErrorResult& aRv) {
    130  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GenerateIdentity()"));
    131 
    132  // Create a new Promise object for the result
    133  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    134  if (NS_WARN_IF(aRv.Failed())) {
    135    return nullptr;
    136  }
    137 
    138  mTransactionChild->SendRequestGenerateIdentityKeypair()->Then(
    139      GetCurrentSerialEventTarget(), __func__,
    140      [promise, self = RefPtr{this}](Maybe<RawBytes>&& result) {
    141        // Check if the value is Nothing
    142        if (result.isNothing()) {
    143          promise->MaybeRejectWithUnknownError(
    144              "generateIdentityKeypair failed");
    145          return;
    146        }
    147 
    148        // Get the context from the GlobalObject
    149        AutoJSAPI jsapi;
    150        if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
    151          promise->MaybeRejectWithUnknownError(
    152              "generateIdentityKeypair failed");
    153          return;
    154        }
    155        JSContext* cx = jsapi.cx();
    156 
    157        // Construct the Uint8Array object
    158        ErrorResult error;
    159        JS::Rooted<JSObject*> content(
    160            cx, Uint8Array::Create(cx, result->data(), error));
    161        error.WouldReportJSException();
    162        if (error.Failed()) {
    163          promise->MaybeReject(std::move(error));
    164          return;
    165        }
    166 
    167        // Construct MLSBytes with the client identifer as content
    168        RootedDictionary<MLSBytes> rvalue(cx);
    169        rvalue.mType = MLSObjectType::Client_identifier;
    170        rvalue.mContent.Init(content);
    171 
    172        // Resolve the promise with the MLSBytes object
    173        promise->MaybeResolve(rvalue);
    174      },
    175      [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    176        promise->MaybeRejectWithUnknownError("generateIdentity failed");
    177      });
    178 
    179  return promise.forget();
    180 }
    181 
    182 already_AddRefed<Promise> MLS::GenerateCredential(
    183    const MLSBytesOrUint8ArrayOrUTF8String& aJsCredContent, ErrorResult& aRv) {
    184  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    185          ("MLS::GenerateCredentialBasic()"));
    186 
    187  // Handle the credential content parameter
    188  nsTArray<uint8_t> credContent = ExtractMLSBytesOrUint8ArrayOrUTF8String(
    189      MLSObjectType::Credential_basic, aJsCredContent, aRv);
    190  if (NS_WARN_IF(aRv.Failed())) {
    191    return nullptr;
    192  }
    193 
    194  // Check if the credContent is empty
    195  if (NS_WARN_IF(credContent.IsEmpty())) {
    196    aRv.ThrowTypeError("The credential content must not be empty");
    197    return nullptr;
    198  }
    199 
    200  // Create a new Promise object for the result
    201  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    202  if (NS_WARN_IF(aRv.Failed())) {
    203    return nullptr;
    204  }
    205 
    206  mTransactionChild->SendRequestGenerateCredentialBasic(credContent)
    207      ->Then(
    208          GetCurrentSerialEventTarget(), __func__,
    209          [promise, self = RefPtr{this}](Maybe<RawBytes>&& result) {
    210            // Check if the value is Nothing
    211            if (result.isNothing()) {
    212              promise->MaybeRejectWithUnknownError(
    213                  "generateCredentialBasic failed");
    214              return;
    215            }
    216 
    217            // Get the context from the GlobalObject
    218            AutoJSAPI jsapi;
    219            if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
    220              promise->MaybeRejectWithUnknownError(
    221                  "generateCredentialBasic failed");
    222              return;
    223            }
    224            JSContext* cx = jsapi.cx();
    225 
    226            // Construct the Uint8Array object
    227            ErrorResult error;
    228            JS::Rooted<JSObject*> content(
    229                cx, Uint8Array::Create(cx, result->data(), error));
    230            error.WouldReportJSException();
    231            if (error.Failed()) {
    232              promise->MaybeReject(std::move(error));
    233              return;
    234            }
    235 
    236            // Construct MLSBytes with the client identifer as content
    237            RootedDictionary<MLSBytes> rvalue(cx);
    238            rvalue.mType = MLSObjectType::Credential_basic;
    239            rvalue.mContent.Init(content);
    240 
    241            // Resolve the promise
    242            promise->MaybeResolve(rvalue);
    243          },
    244          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    245            promise->MaybeRejectWithUnknownError(
    246                "generateCredentialBasic failed");
    247          });
    248 
    249  return promise.forget();
    250 }
    251 
    252 already_AddRefed<Promise> MLS::GenerateKeyPackage(
    253    const MLSBytesOrUint8Array& aJsClientIdentifier,
    254    const MLSBytesOrUint8Array& aJsCredential, ErrorResult& aRv) {
    255  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GenerateKeyPackage()"));
    256 
    257  // Handle the client identifier parameter
    258  nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
    259      MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
    260  if (NS_WARN_IF(aRv.Failed())) {
    261    return nullptr;
    262  }
    263 
    264  // Check if the client identifier is empty
    265  if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
    266    aRv.ThrowTypeError("The client identifier must not be empty");
    267    return nullptr;
    268  }
    269 
    270  // Handle the credential parameter
    271  nsTArray<uint8_t> credential = ExtractMLSBytesOrUint8Array(
    272      MLSObjectType::Credential_basic, aJsCredential, aRv);
    273  if (NS_WARN_IF(aRv.Failed())) {
    274    return nullptr;
    275  }
    276 
    277  // Check if the credential is empty
    278  if (NS_WARN_IF(credential.IsEmpty())) {
    279    aRv.ThrowTypeError("The credential must not be empty");
    280    return nullptr;
    281  }
    282 
    283  // Create a new Promise object for the result
    284  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    285  if (NS_WARN_IF(aRv.Failed())) {
    286    return nullptr;
    287  }
    288 
    289  // Use the static method or instance to send the IPC message
    290  mTransactionChild->SendRequestGenerateKeyPackage(clientIdentifier, credential)
    291      ->Then(
    292          GetCurrentSerialEventTarget(), __func__,
    293          [promise, self = RefPtr{this}](Maybe<RawBytes>&& keyPackage) {
    294            // Check if the value is Nothing
    295            if (keyPackage.isNothing()) {
    296              promise->MaybeReject(NS_ERROR_FAILURE);
    297              return;
    298            }
    299 
    300            // Get the context from the GlobalObject
    301            AutoJSAPI jsapi;
    302            if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
    303              promise->MaybeReject(NS_ERROR_FAILURE);
    304              return;
    305            }
    306            JSContext* cx = jsapi.cx();
    307 
    308            // Construct the Uint8Array object
    309            ErrorResult error;
    310            JS::Rooted<JSObject*> content(
    311                cx, Uint8Array::Create(cx, keyPackage->data(), error));
    312            error.WouldReportJSException();
    313            if (error.Failed()) {
    314              promise->MaybeReject(std::move(error));
    315              return;
    316            }
    317 
    318            // Construct MLSBytes with the client identifer as content
    319            RootedDictionary<MLSBytes> rvalue(cx);
    320            rvalue.mType = MLSObjectType::Key_package;
    321            rvalue.mContent.Init(content);
    322 
    323            // Resolve the promise
    324            promise->MaybeResolve(rvalue);
    325          },
    326          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    327            promise->MaybeRejectWithUnknownError("generateKeyPackage failed");
    328          });
    329 
    330  return promise.forget();
    331 }
    332 
    333 already_AddRefed<Promise> MLS::GroupCreate(
    334    const MLSBytesOrUint8Array& aJsClientIdentifier,
    335    const MLSBytesOrUint8Array& aJsCredential, ErrorResult& aRv) {
    336  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupCreate()"));
    337 
    338  // Handle the client identifier parameter
    339  nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
    340      MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
    341  if (NS_WARN_IF(aRv.Failed())) {
    342    return nullptr;
    343  }
    344 
    345  // Check if the client identifier is empty
    346  if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
    347    aRv.ThrowTypeError("The client identifier must not be empty");
    348    return nullptr;
    349  }
    350 
    351  // Handle the credential parameter
    352  nsTArray<uint8_t> credential = ExtractMLSBytesOrUint8Array(
    353      MLSObjectType::Credential_basic, aJsCredential, aRv);
    354  if (NS_WARN_IF(aRv.Failed())) {
    355    return nullptr;
    356  }
    357 
    358  // Check if the credential is empty
    359  if (NS_WARN_IF(credential.IsEmpty())) {
    360    aRv.ThrowTypeError("The credential must not be empty");
    361    return nullptr;
    362  }
    363 
    364  // Log the hex of clientIdentifier
    365  if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
    366    nsAutoCString clientIdHex;
    367    for (uint8_t byte : clientIdentifier) {
    368      clientIdHex.AppendPrintf("%02X", byte);
    369    }
    370    MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    371            ("clientIdentifier in hex: %s\n", clientIdHex.get()));
    372  }
    373 
    374  // Initialize jsGroupIdentifier to one byte of value 0xFF.
    375  // We do not want to allow choosing the GID at this point.
    376  // This value not being of the correct length will be discarded
    377  // internally and a fresh GID will be generated.
    378  //
    379  // In the future, the caller will allow choosing the GID.
    380  AutoTArray<uint8_t, 1> groupIdentifier{0xFF};
    381 
    382  // Create a new Promise object for the result
    383  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    384  if (NS_WARN_IF(aRv.Failed())) {
    385    return nullptr;
    386  }
    387 
    388  // Use the static method or instance to send the IPC message
    389  mTransactionChild
    390      ->SendRequestGroupCreate(clientIdentifier, credential, groupIdentifier)
    391      ->Then(
    392          GetCurrentSerialEventTarget(), __func__,
    393          [promise, self = RefPtr{this},
    394           clientIdentifier(std::move(clientIdentifier))](
    395              Maybe<mozilla::security::mls::GkGroupIdEpoch>&&
    396                  groupIdEpoch) mutable {
    397            // Check if the value is Nothing
    398            if (groupIdEpoch.isNothing()) {
    399              promise->MaybeReject(NS_ERROR_FAILURE);
    400              return;
    401            }
    402 
    403            RefPtr<MLSGroupView> group =
    404                new MLSGroupView(self, std::move(groupIdEpoch->group_id),
    405                                 std::move(clientIdentifier));
    406 
    407            promise->MaybeResolve(group);
    408          },
    409          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    410            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    411                    ("IPC message rejected with reason: %d",
    412                     static_cast<int>(aReason)));
    413            promise->MaybeRejectWithUnknownError("groupCreate failed");
    414          });
    415 
    416  return promise.forget();
    417 }
    418 
    419 already_AddRefed<mozilla::dom::Promise> MLS::GroupGet(
    420    const MLSBytesOrUint8Array& aJsGroupIdentifier,
    421    const MLSBytesOrUint8Array& aJsClientIdentifier, ErrorResult& aRv) {
    422  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupGet()"));
    423 
    424  // Handle the group identifier parameter
    425  nsTArray<uint8_t> groupIdentifier = ExtractMLSBytesOrUint8Array(
    426      MLSObjectType::Group_identifier, aJsGroupIdentifier, aRv);
    427  if (NS_WARN_IF(aRv.Failed())) {
    428    return nullptr;
    429  }
    430 
    431  // Check if the group identifier is empty
    432  if (NS_WARN_IF(groupIdentifier.IsEmpty())) {
    433    aRv.ThrowTypeError("The group identifier must not be empty");
    434    return nullptr;
    435  }
    436 
    437  // Handle the client identifier parameter
    438  nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
    439      MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
    440  if (NS_WARN_IF(aRv.Failed())) {
    441    return nullptr;
    442  }
    443 
    444  // Check if the client identifier is empty
    445  if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
    446    aRv.ThrowTypeError("The client identifier must not be empty");
    447    return nullptr;
    448  }
    449 
    450  // Create a new Promise object for the result
    451  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    452  if (NS_WARN_IF(aRv.Failed())) {
    453    return nullptr;
    454  }
    455 
    456  // Initialize label, context and len
    457  // We pass this through IPC to be able to reuse the same code for different
    458  // labels in the future
    459  AutoTArray<uint8_t, 7> label{'l', 'i', 'v', 'e', 'n', 'e', 's', 's'};
    460  AutoTArray<uint8_t, 1> context{0x00};
    461  uint64_t len = 32;
    462 
    463  // Use the static method or instance to send the IPC message
    464  mTransactionChild
    465      ->SendRequestExportSecret(groupIdentifier, clientIdentifier, label,
    466                                context, len)
    467      ->Then(
    468          GetCurrentSerialEventTarget(), __func__,
    469          [promise, self = RefPtr{this},
    470           groupIdentifier(std::move(groupIdentifier)),
    471           clientIdentifier(std::move(clientIdentifier))](
    472              Maybe<mozilla::security::mls::GkExporterOutput>&&
    473                  exporterOutput) mutable {
    474            // Check if the exporterOutput contains a value
    475            if (exporterOutput.isNothing()) {
    476              promise->MaybeReject(NS_ERROR_FAILURE);
    477              return;
    478            }
    479 
    480            RefPtr<MLSGroupView> group =
    481                new MLSGroupView(self, std::move(exporterOutput->group_id),
    482                                 std::move(clientIdentifier));
    483            promise->MaybeResolve(group);
    484          },
    485          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    486            promise->MaybeRejectWithUnknownError("exportSecret failed");
    487          });
    488 
    489  return promise.forget();
    490 }
    491 
    492 already_AddRefed<Promise> MLS::GroupJoin(
    493    const MLSBytesOrUint8Array& aJsClientIdentifier,
    494    const MLSBytesOrUint8Array& aJsWelcome, ErrorResult& aRv) {
    495  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupJoin()"));
    496 
    497  // Handle the client identifier parameter
    498  nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
    499      MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
    500  if (NS_WARN_IF(aRv.Failed())) {
    501    return nullptr;
    502  }
    503 
    504  // Check if the client identifier is empty
    505  if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
    506    aRv.ThrowTypeError("The client identifier must not be empty");
    507    return nullptr;
    508  }
    509 
    510  // Handle the welcome parameter
    511  nsTArray<uint8_t> welcome =
    512      ExtractMLSBytesOrUint8Array(MLSObjectType::Welcome, aJsWelcome, aRv);
    513  if (NS_WARN_IF(aRv.Failed())) {
    514    return nullptr;
    515  }
    516 
    517  // Check if the welcome is empty
    518  if (NS_WARN_IF(welcome.IsEmpty())) {
    519    aRv.ThrowTypeError("The welcome must not be empty");
    520    return nullptr;
    521  }
    522 
    523  // Create a new Promise object for the result
    524  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    525  if (NS_WARN_IF(aRv.Failed())) {
    526    return nullptr;
    527  }
    528 
    529  mTransactionChild->SendRequestGroupJoin(clientIdentifier, welcome)
    530      ->Then(
    531          GetCurrentSerialEventTarget(), __func__,
    532          [promise, self = RefPtr{this},
    533           clientIdentifier(std::move(clientIdentifier))](
    534              Maybe<mozilla::security::mls::GkGroupIdEpoch>&&
    535                  groupIdEpoch) mutable {
    536            // Check if the value is Nothing
    537            if (groupIdEpoch.isNothing()) {
    538              promise->MaybeReject(NS_ERROR_FAILURE);
    539              return;
    540            }
    541 
    542            // Returns groupId and epoch
    543            RefPtr<MLSGroupView> group =
    544                new MLSGroupView(self, std::move(groupIdEpoch->group_id),
    545                                 std::move(clientIdentifier));
    546 
    547            // Resolve the promise
    548            promise->MaybeResolve(group);
    549          },
    550          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    551            promise->MaybeRejectWithUnknownError("groupJoin failed");
    552          });
    553 
    554  return promise.forget();
    555 }
    556 
    557 already_AddRefed<Promise> MLS::GetGroupIdFromMessage(
    558    const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv) {
    559  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GetGroupIdFromMessage()"));
    560 
    561  // Handle the message parameter
    562  nsTArray<uint8_t> message =
    563      ExtractMLSBytesOrUint8ArrayWithUnknownType(aJsMessage, aRv);
    564  if (NS_WARN_IF(aRv.Failed())) {
    565    return nullptr;
    566  }
    567 
    568  // Check if the message is empty
    569  if (NS_WARN_IF(message.IsEmpty())) {
    570    aRv.ThrowTypeError("The message must not be empty");
    571    return nullptr;
    572  }
    573 
    574  // Create a new Promise object for the result
    575  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    576  if (NS_WARN_IF(aRv.Failed())) {
    577    return nullptr;
    578  }
    579 
    580  mTransactionChild->SendRequestGetGroupIdentifier(message)->Then(
    581      GetCurrentSerialEventTarget(), __func__,
    582      [promise, self = RefPtr{this},
    583       message(std::move(message))](Maybe<RawBytes>&& result) {
    584        // Check if the value is Nothing
    585        if (result.isNothing()) {
    586          promise->MaybeReject(NS_ERROR_FAILURE);
    587          return;
    588        }
    589 
    590        // Get the context from the GlobalObject
    591        AutoJSAPI jsapi;
    592        if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
    593          MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    594                  ("Failed to initialize JSAPI"));
    595          promise->MaybeReject(NS_ERROR_FAILURE);
    596          return;
    597        }
    598        JSContext* cx = jsapi.cx();
    599 
    600        // Construct the Uint8Array objects based on the tag
    601        ErrorResult error;
    602        JS::Rooted<JSObject*> jsGroupId(
    603            cx, Uint8Array::Create(cx, result->data(), error));
    604        error.WouldReportJSException();
    605        if (error.Failed()) {
    606          promise->MaybeReject(std::move(error));
    607          return;
    608        }
    609 
    610        // Construct the MLSBytes object for the groupId
    611        RootedDictionary<MLSBytes> rvalue(cx);
    612        rvalue.mType = MLSObjectType::Group_identifier;
    613        rvalue.mContent.Init(jsGroupId);
    614 
    615        // Log if in debug mode
    616        if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
    617          MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    618                  ("Successfully constructed MLSBytes"));
    619        }
    620 
    621        // Resolve the promise
    622        promise->MaybeResolve(rvalue);
    623      },
    624      [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    625        MOZ_LOG(
    626            gMlsLog, mozilla::LogLevel::Error,
    627            ("IPC call rejected with reason: %d", static_cast<int>(aReason)));
    628        promise->MaybeRejectWithUnknownError("getGroupIdFromMessage failed");
    629      });
    630 
    631  return promise.forget();
    632 }
    633 
    634 already_AddRefed<Promise> MLS::GetGroupEpochFromMessage(
    635    const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv) {
    636  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    637          ("MLS::GetGroupEpochFromMessage()"));
    638 
    639  // Handle the message parameter
    640  nsTArray<uint8_t> message =
    641      ExtractMLSBytesOrUint8ArrayWithUnknownType(aJsMessage, aRv);
    642  if (NS_WARN_IF(aRv.Failed())) {
    643    return nullptr;
    644  }
    645 
    646  // Check if the message is empty
    647  if (NS_WARN_IF(message.IsEmpty())) {
    648    aRv.ThrowTypeError("The message must not be empty");
    649    return nullptr;
    650  }
    651 
    652  // Create a new Promise object for the result
    653  RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
    654  if (NS_WARN_IF(aRv.Failed())) {
    655    return nullptr;
    656  }
    657 
    658  mTransactionChild->SendRequestGetGroupEpoch(message)->Then(
    659      GetCurrentSerialEventTarget(), __func__,
    660      [promise, self = RefPtr{this},
    661       message(std::move(message))](Maybe<RawBytes>&& result) {
    662        // Check if the value is Nothing
    663        if (result.isNothing()) {
    664          promise->MaybeReject(NS_ERROR_FAILURE);
    665          return;
    666        }
    667 
    668        // Get the context from the GlobalObject
    669        AutoJSAPI jsapi;
    670        if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
    671          MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    672                  ("Failed to initialize JSAPI"));
    673          promise->MaybeReject(NS_ERROR_FAILURE);
    674          return;
    675        }
    676        JSContext* cx = jsapi.cx();
    677 
    678        // Construct the Uint8Array objects based on the tag
    679        ErrorResult error;
    680        JS::Rooted<JSObject*> jsGroupId(
    681            cx, Uint8Array::Create(cx, result->data(), error));
    682        error.WouldReportJSException();
    683        if (error.Failed()) {
    684          promise->MaybeReject(std::move(error));
    685          return;
    686        }
    687 
    688        // Construct the MLSBytes object for the groupId
    689        RootedDictionary<MLSBytes> rvalue(cx);
    690        rvalue.mType = MLSObjectType::Group_epoch;
    691        rvalue.mContent.Init(jsGroupId);
    692 
    693        // Log if in debug mode
    694        if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
    695          MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    696                  ("Successfully constructed MLSBytes"));
    697        }
    698 
    699        // Resolve the promise
    700        promise->MaybeResolve(rvalue);
    701      },
    702      [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    703        MOZ_LOG(
    704            gMlsLog, mozilla::LogLevel::Error,
    705            ("IPC call rejected with reason: %d", static_cast<int>(aReason)));
    706        promise->MaybeRejectWithUnknownError("getGroupEpochFromMessage failed");
    707      });
    708 
    709  return promise.forget();
    710 }
    711 
    712 }  // namespace mozilla::dom