tor-browser

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

MLSGroupView.cpp (49866B)


      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 "MLSGroupView.h"
      8 
      9 #include "MLSTypeUtils.h"
     10 #include "ipc/IPCMessageUtilsSpecializations.h"
     11 #include "mozilla/BasePrincipal.h"
     12 #include "mozilla/Logging.h"
     13 #include "mozilla/dom/MLSBinding.h"
     14 #include "mozilla/dom/MLSTransactionChild.h"
     15 #include "mozilla/dom/MLSTransactionMessage.h"
     16 #include "mozilla/dom/Promise.h"
     17 #include "mozilla/dom/TypedArray.h"
     18 #include "nsDebug.h"
     19 #include "nsTArray.h"
     20 namespace mozilla::dom {
     21 
     22 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WITH_JS_MEMBERS(MLSGroupView, (mMLS),
     23                                                      (mJsGroupId, mJsClientId))
     24 
     25 NS_IMPL_CYCLE_COLLECTING_ADDREF(MLSGroupView)
     26 NS_IMPL_CYCLE_COLLECTING_RELEASE(MLSGroupView)
     27 
     28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MLSGroupView)
     29  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     30  NS_INTERFACE_MAP_ENTRY(nsISupports)
     31 NS_INTERFACE_MAP_END
     32 
     33 // Setup logging
     34 extern mozilla::LazyLogModule gMlsLog;
     35 
     36 MLSGroupView::MLSGroupView(MLS* aMLS, nsTArray<uint8_t>&& aGroupId,
     37                           nsTArray<uint8_t>&& aClientId)
     38    : mMLS(aMLS),
     39      mGroupId(std::move(aGroupId)),
     40      mClientId(std::move(aClientId)) {
     41  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::MLSGroupView()"));
     42 
     43  // Indicate that the object holds JS objects
     44  mozilla::HoldJSObjects(this);
     45 }
     46 
     47 JSObject* MLSGroupView::WrapObject(JSContext* aCx,
     48                                   JS::Handle<JSObject*> aGivenProto) {
     49  return MLSGroupView_Binding::Wrap(aCx, this, aGivenProto);
     50 }
     51 
     52 //
     53 // API
     54 //
     55 
     56 void MLSGroupView::GetGroupId(JSContext* aCx,
     57                              JS::MutableHandle<JSObject*> aGroupId,
     58                              ErrorResult& aRv) {
     59  if (!mJsGroupId) {
     60    mJsGroupId = Uint8Array::Create(aCx, this, mGroupId, aRv);
     61    if (aRv.Failed()) {
     62      return;
     63    }
     64  }
     65  aGroupId.set(mJsGroupId);
     66 }
     67 
     68 void MLSGroupView::GetClientId(JSContext* aCx,
     69                               JS::MutableHandle<JSObject*> aClientId,
     70                               ErrorResult& aRv) {
     71  if (!mJsClientId) {
     72    mJsClientId = Uint8Array::Create(aCx, this, mClientId, aRv);
     73    if (aRv.Failed()) {
     74      return;
     75    }
     76  }
     77  aClientId.set(mJsClientId);
     78 }
     79 
     80 already_AddRefed<Promise> MLSGroupView::DeleteState(ErrorResult& aRv) {
     81  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::DeleteState()"));
     82 
     83  // Create a new Promise object for the result
     84  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
     85  if (NS_WARN_IF(aRv.Failed())) {
     86    return nullptr;
     87  }
     88 
     89  mMLS->mTransactionChild->SendRequestGroupStateDelete(mGroupId, mClientId)
     90      ->Then(
     91          GetCurrentSerialEventTarget(), __func__,
     92          [promise](
     93              Maybe<mozilla::security::mls::GkGroupIdEpoch>&& groupIdEpoch) {
     94            // Check if the value is Nothing or Some with an empty group_epoch
     95            if (groupIdEpoch.isNothing()) {
     96              promise->MaybeRejectWithUnknownError(
     97                  "Failed to delete group state");
     98              return;
     99            }
    100 
    101            // Check if the epoch is 0xFFFF..FF
    102            bool isMaxEpoch =
    103                std::all_of(groupIdEpoch->group_epoch.begin(),
    104                            groupIdEpoch->group_epoch.end(),
    105                            [](uint8_t byte) { return byte == 0xFF; });
    106 
    107            // If the epoch is 0xFFFF..FF, then the group has been deleted
    108            if (isMaxEpoch) {
    109              promise->MaybeResolveWithUndefined();
    110            } else {
    111              promise->MaybeRejectWithUnknownError(
    112                  "Group has not been deleted");
    113            }
    114          },
    115          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    116            promise->MaybeRejectWithUnknownError(
    117                "Failed to delete group state");
    118          });
    119 
    120  return promise.forget();
    121 }
    122 
    123 already_AddRefed<Promise> MLSGroupView::Add(
    124    const MLSBytesOrUint8Array& aJsKeyPackage, ErrorResult& aRv) {
    125  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Add()"));
    126 
    127  // Handle the key package parameter
    128  nsTArray<uint8_t> keyPackage = ExtractMLSBytesOrUint8Array(
    129      MLSObjectType::Key_package, aJsKeyPackage, aRv);
    130  if (NS_WARN_IF(aRv.Failed())) {
    131    return nullptr;
    132  }
    133 
    134  // Check if the key package is empty
    135  if (NS_WARN_IF(keyPackage.IsEmpty())) {
    136    aRv.ThrowTypeError("The key package must not be empty");
    137    return nullptr;
    138  }
    139 
    140  // Create a new Promise object for the result
    141  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    142  if (NS_WARN_IF(aRv.Failed())) {
    143    return nullptr;
    144  }
    145 
    146  mMLS->mTransactionChild->SendRequestGroupAdd(mGroupId, mClientId, keyPackage)
    147      ->Then(
    148          GetCurrentSerialEventTarget(), __func__,
    149          [promise, self = RefPtr<MLSGroupView>(this)](
    150              Maybe<mozilla::security::mls::GkMlsCommitOutput>&& commitOutput) {
    151            // Check if the value is Nothing
    152            if (commitOutput.isNothing()) {
    153              promise->MaybeReject(NS_ERROR_FAILURE);
    154              return;
    155            }
    156 
    157            // Get the context from the GlobalObject
    158            AutoJSAPI jsapi;
    159            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    160              promise->MaybeReject(NS_ERROR_FAILURE);
    161              return;
    162            }
    163            JSContext* cx = jsapi.cx();
    164 
    165            // Construct the Uint8Array objects
    166            ErrorResult error;
    167            JS::Rooted<JSObject*> jsGroupId(
    168                cx, Uint8Array::Create(cx, self->mGroupId, error));
    169            error.WouldReportJSException();
    170            if (error.Failed()) {
    171              promise->MaybeReject(std::move(error));
    172              return;
    173            }
    174            JS::Rooted<JSObject*> jsClientId(
    175                cx, Uint8Array::Create(cx, commitOutput->identity, error));
    176            error.WouldReportJSException();
    177            if (error.Failed()) {
    178              promise->MaybeReject(std::move(error));
    179              return;
    180            }
    181            JS::Rooted<JSObject*> jsCommit(
    182                cx, Uint8Array::Create(cx, commitOutput->commit, error));
    183            error.WouldReportJSException();
    184            if (error.Failed()) {
    185              promise->MaybeReject(std::move(error));
    186              return;
    187            }
    188            JS::Rooted<JSObject*> jsWelcome(
    189                cx, Uint8Array::Create(cx, commitOutput->welcome, error));
    190            error.WouldReportJSException();
    191            if (error.Failed()) {
    192              promise->MaybeReject(std::move(error));
    193              return;
    194            }
    195            JS::Rooted<JSObject*> jsGroupInfo(
    196                cx, Uint8Array::Create(cx, commitOutput->group_info, error));
    197            error.WouldReportJSException();
    198            if (error.Failed()) {
    199              promise->MaybeReject(std::move(error));
    200              return;
    201            }
    202            JS::Rooted<JSObject*> jsRatchetTree(
    203                cx, Uint8Array::Create(cx, commitOutput->ratchet_tree, error));
    204            error.WouldReportJSException();
    205            if (error.Failed()) {
    206              promise->MaybeReject(std::move(error));
    207              return;
    208            }
    209 
    210            // Construct MLSCommitOutput with the parsed data
    211            RootedDictionary<MLSCommitOutput> rvalue(cx);
    212            rvalue.mType = MLSObjectType::Commit_output;
    213            rvalue.mGroupId.Init(jsGroupId);
    214            rvalue.mCommit.Init(jsCommit);
    215            if (!commitOutput->welcome.IsEmpty()) {
    216              rvalue.mWelcome.Construct();
    217              rvalue.mWelcome.Value().Init(jsWelcome);
    218            }
    219            if (!commitOutput->group_info.IsEmpty()) {
    220              rvalue.mGroupInfo.Construct();
    221              rvalue.mGroupInfo.Value().Init(jsGroupInfo);
    222            }
    223            if (!commitOutput->ratchet_tree.IsEmpty()) {
    224              rvalue.mRatchetTree.Construct();
    225              rvalue.mRatchetTree.Value().Init(jsRatchetTree);
    226            }
    227            if (!commitOutput->identity.IsEmpty()) {
    228              rvalue.mClientId.Construct();
    229              rvalue.mClientId.Value().Init(jsClientId);
    230            }
    231 
    232            // Resolve the promise
    233            promise->MaybeResolve(rvalue);
    234          },
    235          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    236            promise->MaybeRejectWithUnknownError("Failed to add to group");
    237          });
    238 
    239  return promise.forget();
    240 }
    241 
    242 already_AddRefed<Promise> MLSGroupView::ProposeAdd(
    243    const MLSBytesOrUint8Array& aJsKeyPackage, ErrorResult& aRv) {
    244  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::ProposeAdd()"));
    245 
    246  // Handle the key package parameter
    247  nsTArray<uint8_t> keyPackage = ExtractMLSBytesOrUint8Array(
    248      MLSObjectType::Key_package, aJsKeyPackage, aRv);
    249  if (NS_WARN_IF(aRv.Failed())) {
    250    return nullptr;
    251  }
    252 
    253  // Check if the key package is empty
    254  if (NS_WARN_IF(keyPackage.IsEmpty())) {
    255    aRv.ThrowTypeError("The key package must not be empty");
    256    return nullptr;
    257  }
    258 
    259  // Create a new Promise object for the result
    260  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    261  if (NS_WARN_IF(aRv.Failed())) {
    262    return nullptr;
    263  }
    264 
    265  mMLS->mTransactionChild
    266      ->SendRequestGroupProposeAdd(mGroupId, mClientId, keyPackage)
    267      ->Then(
    268          GetCurrentSerialEventTarget(), __func__,
    269          [promise,
    270           self = RefPtr<MLSGroupView>(this)](Maybe<RawBytes>&& proposal) {
    271            // Check if the value is Nothing
    272            if (proposal.isNothing()) {
    273              promise->MaybeRejectWithUnknownError(
    274                  "Failed to propose add to group");
    275              return;
    276            }
    277 
    278            // Get the context from the GlobalObject
    279            AutoJSAPI jsapi;
    280            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    281              promise->MaybeReject(NS_ERROR_FAILURE);
    282              return;
    283            }
    284            JSContext* cx = jsapi.cx();
    285 
    286            // Construct the Uint8Array object
    287            ErrorResult error;
    288            JS::Rooted<JSObject*> content(
    289                cx, Uint8Array::Create(cx, proposal->data(), error));
    290            error.WouldReportJSException();
    291            if (error.Failed()) {
    292              promise->MaybeReject(std::move(error));
    293              return;
    294            }
    295 
    296            // Construct MLSBytes with the proposal as content
    297            RootedDictionary<MLSBytes> rvalue(cx);
    298            rvalue.mType = MLSObjectType::Proposal;
    299            rvalue.mContent.Init(content);
    300 
    301            // Resolve the promise
    302            promise->MaybeResolve(rvalue);
    303          },
    304          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    305            promise->MaybeRejectWithUnknownError(
    306                "Failed to propose add to group");
    307          });
    308 
    309  return promise.forget();
    310 }
    311 
    312 already_AddRefed<Promise> MLSGroupView::Remove(
    313    const MLSBytesOrUint8Array& aJsRemClientIdentifier, ErrorResult& aRv) {
    314  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Remove()"));
    315 
    316  // Handle the remove client identifier parameter
    317  nsTArray<uint8_t> remClientIdentifier = ExtractMLSBytesOrUint8Array(
    318      MLSObjectType::Client_identifier, aJsRemClientIdentifier, aRv);
    319  if (NS_WARN_IF(aRv.Failed())) {
    320    return nullptr;
    321  }
    322 
    323  // Check if the remove client identifier is empty
    324  if (NS_WARN_IF(remClientIdentifier.IsEmpty())) {
    325    aRv.ThrowTypeError("The remove client identifier must not be empty");
    326    return nullptr;
    327  }
    328 
    329  // Create a new Promise object for the result
    330  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    331  if (NS_WARN_IF(aRv.Failed())) {
    332    return nullptr;
    333  }
    334 
    335  // Use the static method or instance to send the IPC message
    336  mMLS->mTransactionChild
    337      ->SendRequestGroupRemove(mGroupId, mClientId, remClientIdentifier)
    338      ->Then(
    339          GetCurrentSerialEventTarget(), __func__,
    340          [promise, self = RefPtr<MLSGroupView>(this)](
    341              Maybe<mozilla::security::mls::GkMlsCommitOutput>&& commitOutput) {
    342            // Check if the value is Nothing
    343            if (commitOutput.isNothing()) {
    344              promise->MaybeReject(NS_ERROR_FAILURE);
    345              return;
    346            }
    347 
    348            // Get the context from the GlobalObject
    349            AutoJSAPI jsapi;
    350            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    351              promise->MaybeReject(NS_ERROR_FAILURE);
    352              return;
    353            }
    354            JSContext* cx = jsapi.cx();
    355 
    356            // Construct the Uint8Array objects
    357            ErrorResult error;
    358            JS::Rooted<JSObject*> jsGroupId(
    359                cx, Uint8Array::Create(cx, self->mGroupId, error));
    360            error.WouldReportJSException();
    361            if (error.Failed()) {
    362              promise->MaybeReject(std::move(error));
    363              return;
    364            }
    365            JS::Rooted<JSObject*> jsClientId(
    366                cx, Uint8Array::Create(cx, commitOutput->identity, error));
    367            error.WouldReportJSException();
    368            if (error.Failed()) {
    369              promise->MaybeReject(std::move(error));
    370              return;
    371            }
    372            JS::Rooted<JSObject*> jsCommit(
    373                cx, Uint8Array::Create(cx, commitOutput->commit, error));
    374            error.WouldReportJSException();
    375            if (error.Failed()) {
    376              promise->MaybeReject(std::move(error));
    377              return;
    378            }
    379            JS::Rooted<JSObject*> jsWelcome(
    380                cx, Uint8Array::Create(cx, commitOutput->welcome, error));
    381            error.WouldReportJSException();
    382            if (error.Failed()) {
    383              promise->MaybeReject(std::move(error));
    384              return;
    385            }
    386            JS::Rooted<JSObject*> jsGroupInfo(
    387                cx, Uint8Array::Create(cx, commitOutput->group_info, error));
    388            error.WouldReportJSException();
    389            if (error.Failed()) {
    390              promise->MaybeReject(std::move(error));
    391              return;
    392            }
    393            JS::Rooted<JSObject*> jsRatchetTree(
    394                cx, Uint8Array::Create(cx, commitOutput->ratchet_tree, error));
    395            error.WouldReportJSException();
    396            if (error.Failed()) {
    397              promise->MaybeReject(std::move(error));
    398              return;
    399            }
    400 
    401            // Construct MLSCommitOutput with the parsed data
    402            RootedDictionary<MLSCommitOutput> rvalue(cx);
    403            rvalue.mType = MLSObjectType::Commit_output;
    404            rvalue.mGroupId.Init(jsGroupId);
    405            rvalue.mCommit.Init(jsCommit);
    406            if (!commitOutput->welcome.IsEmpty()) {
    407              rvalue.mWelcome.Construct();
    408              rvalue.mWelcome.Value().Init(jsWelcome);
    409            }
    410            if (!commitOutput->group_info.IsEmpty()) {
    411              rvalue.mGroupInfo.Construct();
    412              rvalue.mGroupInfo.Value().Init(jsGroupInfo);
    413            }
    414            if (!commitOutput->ratchet_tree.IsEmpty()) {
    415              rvalue.mRatchetTree.Construct();
    416              rvalue.mRatchetTree.Value().Init(jsRatchetTree);
    417            }
    418            if (!commitOutput->identity.IsEmpty()) {
    419              rvalue.mClientId.Construct();
    420              rvalue.mClientId.Value().Init(jsClientId);
    421            }
    422 
    423            // Resolve the promise
    424            promise->MaybeResolve(rvalue);
    425          },
    426          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    427            promise->MaybeRejectWithUnknownError("Failed to remove from group");
    428          });
    429 
    430  return promise.forget();
    431 }
    432 
    433 already_AddRefed<Promise> MLSGroupView::ProposeRemove(
    434    const MLSBytesOrUint8Array& aJsRemClientIdentifier, ErrorResult& aRv) {
    435  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::ProposeRemove()"));
    436 
    437  // Handle the remove client identifier parameter
    438  nsTArray<uint8_t> remClientIdentifier = ExtractMLSBytesOrUint8Array(
    439      MLSObjectType::Client_identifier, aJsRemClientIdentifier, aRv);
    440  if (NS_WARN_IF(aRv.Failed())) {
    441    return nullptr;
    442  }
    443 
    444  // Check if the removed client identifier is empty
    445  if (NS_WARN_IF(remClientIdentifier.IsEmpty())) {
    446    aRv.ThrowTypeError("The removed 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(mMLS->GetParentObject(), aRv);
    452  if (NS_WARN_IF(aRv.Failed())) {
    453    return nullptr;
    454  }
    455 
    456  mMLS->mTransactionChild
    457      ->SendRequestGroupProposeRemove(mGroupId, mClientId, remClientIdentifier)
    458      ->Then(
    459          GetCurrentSerialEventTarget(), __func__,
    460          [promise,
    461           self = RefPtr<MLSGroupView>(this)](Maybe<RawBytes>&& proposal) {
    462            // Check if the value is Nothing
    463            if (proposal.isNothing()) {
    464              promise->MaybeReject(NS_ERROR_FAILURE);
    465              return;
    466            }
    467 
    468            // Get the context from the GlobalObject
    469            AutoJSAPI jsapi;
    470            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    471              promise->MaybeReject(NS_ERROR_FAILURE);
    472              return;
    473            }
    474            JSContext* cx = jsapi.cx();
    475 
    476            // Construct the Uint8Array object
    477            ErrorResult error;
    478            JS::Rooted<JSObject*> content(
    479                cx, Uint8Array::Create(cx, proposal->data(), error));
    480            error.WouldReportJSException();
    481            if (error.Failed()) {
    482              promise->MaybeReject(std::move(error));
    483              return;
    484            }
    485 
    486            // Construct MLSBytes with the proposal as content
    487            RootedDictionary<MLSBytes> rvalue(cx);
    488            rvalue.mType = MLSObjectType::Proposal;
    489            rvalue.mContent.Init(content);
    490 
    491            // Resolve the promise
    492            promise->MaybeResolve(rvalue);
    493          },
    494          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    495            promise->MaybeRejectWithUnknownError(
    496                "Failed to propose remove from group");
    497          });
    498 
    499  return promise.forget();
    500 }
    501 
    502 already_AddRefed<Promise> MLSGroupView::Close(ErrorResult& aRv) {
    503  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Close()"));
    504 
    505  // Create a new Promise object for the result
    506  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    507  if (NS_WARN_IF(aRv.Failed())) {
    508    return nullptr;
    509  }
    510 
    511  mMLS->mTransactionChild->SendRequestGroupClose(mGroupId, mClientId)
    512      ->Then(
    513          GetCurrentSerialEventTarget(), __func__,
    514          [promise, self = RefPtr<MLSGroupView>(this)](
    515              Maybe<mozilla::security::mls::GkMlsCommitOutput>&& commitOutput) {
    516            // Check if the value is Nothing
    517            if (commitOutput.isNothing()) {
    518              promise->MaybeReject(NS_ERROR_FAILURE);
    519              return;
    520            }
    521 
    522            // Get the context from the GlobalObject
    523            AutoJSAPI jsapi;
    524            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    525              promise->MaybeReject(NS_ERROR_FAILURE);
    526              return;
    527            }
    528            JSContext* cx = jsapi.cx();
    529 
    530            // Construct the Uint8Array objects
    531            ErrorResult error;
    532            JS::Rooted<JSObject*> jsGroupId(
    533                cx, Uint8Array::Create(cx, self->mGroupId, error));
    534            error.WouldReportJSException();
    535            if (error.Failed()) {
    536              promise->MaybeReject(std::move(error));
    537              return;
    538            }
    539            JS::Rooted<JSObject*> jsClientId(
    540                cx, Uint8Array::Create(cx, commitOutput->identity, error));
    541            error.WouldReportJSException();
    542            if (error.Failed()) {
    543              promise->MaybeReject(std::move(error));
    544              return;
    545            }
    546            JS::Rooted<JSObject*> jsCommit(
    547                cx, Uint8Array::Create(cx, commitOutput->commit, error));
    548            error.WouldReportJSException();
    549            if (error.Failed()) {
    550              promise->MaybeReject(std::move(error));
    551              return;
    552            }
    553            JS::Rooted<JSObject*> jsWelcome(
    554                cx, Uint8Array::Create(cx, commitOutput->welcome, error));
    555            error.WouldReportJSException();
    556            if (error.Failed()) {
    557              promise->MaybeReject(std::move(error));
    558              return;
    559            }
    560            JS::Rooted<JSObject*> jsGroupInfo(
    561                cx, Uint8Array::Create(cx, commitOutput->group_info, error));
    562            error.WouldReportJSException();
    563            if (error.Failed()) {
    564              promise->MaybeReject(std::move(error));
    565              return;
    566            }
    567            JS::Rooted<JSObject*> jsRatchetTree(
    568                cx, Uint8Array::Create(cx, commitOutput->ratchet_tree, error));
    569            error.WouldReportJSException();
    570            if (error.Failed()) {
    571              promise->MaybeReject(std::move(error));
    572              return;
    573            }
    574 
    575            // Construct MLSCommitOutput with the parsed data
    576            RootedDictionary<MLSCommitOutput> rvalue(cx);
    577            rvalue.mType = MLSObjectType::Commit_output;
    578            rvalue.mGroupId.Init(jsGroupId);
    579            rvalue.mCommit.Init(jsCommit);
    580            if (!commitOutput->welcome.IsEmpty()) {
    581              rvalue.mWelcome.Construct();
    582              rvalue.mWelcome.Value().Init(jsWelcome);
    583            }
    584            if (!commitOutput->group_info.IsEmpty()) {
    585              rvalue.mGroupInfo.Construct();
    586              rvalue.mGroupInfo.Value().Init(jsGroupInfo);
    587            }
    588            if (!commitOutput->ratchet_tree.IsEmpty()) {
    589              rvalue.mRatchetTree.Construct();
    590              rvalue.mRatchetTree.Value().Init(jsRatchetTree);
    591            }
    592            if (!commitOutput->identity.IsEmpty()) {
    593              rvalue.mClientId.Construct();
    594              rvalue.mClientId.Value().Init(jsClientId);
    595            }
    596 
    597            // Resolve the promise
    598            promise->MaybeResolve(rvalue);
    599          },
    600          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    601            promise->MaybeRejectWithUnknownError("Failed to close group");
    602          });
    603 
    604  return promise.forget();
    605 }
    606 
    607 already_AddRefed<Promise> MLSGroupView::Details(ErrorResult& aRv) {
    608  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Details()"));
    609 
    610  // Create a new Promise object for the result
    611  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    612  if (NS_WARN_IF(aRv.Failed())) {
    613    return nullptr;
    614  }
    615 
    616  mMLS->mTransactionChild->SendRequestGroupDetails(mGroupId, mClientId)
    617      ->Then(
    618          GetCurrentSerialEventTarget(), __func__,
    619          [promise, self = RefPtr<MLSGroupView>(this)](
    620              Maybe<GkGroupDetails>&& groupDetails) {
    621            // Check if the value is Nothing
    622            if (groupDetails.isNothing()) {
    623              promise->MaybeReject(NS_ERROR_FAILURE);
    624              return;
    625            }
    626 
    627            // Get the context from the GlobalObject
    628            AutoJSAPI jsapi;
    629            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    630              promise->MaybeReject(NS_ERROR_FAILURE);
    631              return;
    632            }
    633            JSContext* cx = jsapi.cx();
    634 
    635            // Construct the Uint8Array objects
    636            ErrorResult error;
    637            JS::Rooted<JSObject*> jsGroupId(
    638                cx, Uint8Array::Create(cx, groupDetails->group_id, error));
    639            error.WouldReportJSException();
    640            if (error.Failed()) {
    641              promise->MaybeReject(std::move(error));
    642              return;
    643            }
    644            JS::Rooted<JSObject*> jsGroupEpoch(
    645                cx, Uint8Array::Create(cx, groupDetails->group_epoch, error));
    646            error.WouldReportJSException();
    647            if (error.Failed()) {
    648              promise->MaybeReject(std::move(error));
    649              return;
    650            }
    651 
    652            // Construct MLSGroupDetails
    653            RootedDictionary<MLSGroupDetails> rvalue(cx);
    654            rvalue.mType = MLSObjectType::Group_info;
    655            rvalue.mGroupId.Init(jsGroupId);
    656            rvalue.mGroupEpoch.Init(jsGroupEpoch);
    657            if (!rvalue.mMembers.SetCapacity(
    658                    groupDetails->group_members.Length(), fallible)) {
    659              promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
    660              return;
    661            }
    662 
    663            for (const auto& member : groupDetails->group_members) {
    664              JS::Rooted<JSObject*> jsClientId(
    665                  cx, Uint8Array::Create(cx, member.identity, error));
    666              error.WouldReportJSException();
    667              if (error.Failed()) {
    668                promise->MaybeReject(std::move(error));
    669                return;
    670              }
    671              JS::Rooted<JSObject*> jsCredential(
    672                  cx, Uint8Array::Create(cx, member.credential, error));
    673              error.WouldReportJSException();
    674              if (error.Failed()) {
    675                promise->MaybeReject(std::move(error));
    676                return;
    677              }
    678 
    679              // Guaranteed not to fail because of the SetCapacity above.
    680              MLSGroupMember& jsMember =
    681                  *rvalue.mMembers.AppendElement(fallible);
    682              jsMember.mClientId.Init(jsClientId);
    683              jsMember.mCredential.Init(jsCredential);
    684            }
    685 
    686            // Resolve the promise
    687            promise->MaybeResolve(rvalue);
    688          },
    689          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    690            promise->MaybeRejectWithUnknownError("Failed to get group details");
    691          });
    692 
    693  return promise.forget();
    694 }
    695 
    696 already_AddRefed<Promise> MLSGroupView::Send(
    697    const MLSBytesOrUint8ArrayOrUTF8String& aJsMessage, ErrorResult& aRv) {
    698  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Send()"));
    699 
    700  // Handle the message parameter
    701  nsTArray<uint8_t> message = ExtractMLSBytesOrUint8ArrayOrUTF8String(
    702      MLSObjectType::Application_message_plaintext, aJsMessage, aRv);
    703  if (NS_WARN_IF(aRv.Failed())) {
    704    return nullptr;
    705  }
    706 
    707  // Create a new Promise object for the result
    708  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    709  if (NS_WARN_IF(aRv.Failed())) {
    710    return nullptr;
    711  }
    712 
    713  mMLS->mTransactionChild->SendRequestSend(mGroupId, mClientId, message)
    714      ->Then(
    715          GetCurrentSerialEventTarget(), __func__,
    716          [promise,
    717           self = RefPtr<MLSGroupView>(this)](Maybe<RawBytes>&& result) {
    718            // Check if the value is Nothing
    719            if (result.isNothing()) {
    720              promise->MaybeReject(NS_ERROR_FAILURE);
    721              return;
    722            }
    723 
    724            // Get the context from the GlobalObject
    725            AutoJSAPI jsapi;
    726            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    727              promise->MaybeReject(NS_ERROR_FAILURE);
    728              return;
    729            }
    730            JSContext* cx = jsapi.cx();
    731 
    732            // Construct the Uint8Array object
    733            ErrorResult error;
    734            JS::Rooted<JSObject*> content(
    735                cx, Uint8Array::Create(cx, result->data(), error));
    736            error.WouldReportJSException();
    737            if (error.Failed()) {
    738              promise->MaybeReject(std::move(error));
    739              return;
    740            }
    741 
    742            // Construct MLSBytes with the group identifier as content
    743            RootedDictionary<MLSBytes> rvalue(cx);
    744            rvalue.mType = MLSObjectType::Application_message_ciphertext;
    745            rvalue.mContent.Init(content);
    746 
    747            promise->MaybeResolve(rvalue);
    748          },
    749          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    750            promise->MaybeRejectWithUnknownError("Failed to send message");
    751          });
    752 
    753  return promise.forget();
    754 }
    755 
    756 already_AddRefed<Promise> MLSGroupView::Receive(
    757    const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv) {
    758  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::Receive()"));
    759 
    760  // Handle the message parameter
    761  nsTArray<uint8_t> message =
    762      ExtractMLSBytesOrUint8ArrayWithUnknownType(aJsMessage, aRv);
    763  if (NS_WARN_IF(aRv.Failed())) {
    764    return nullptr;
    765  }
    766 
    767  // Check if the message is empty
    768  if (NS_WARN_IF(message.IsEmpty())) {
    769    aRv.ThrowTypeError("The receivedmessage must not be empty");
    770    return nullptr;
    771  }
    772 
    773  // Create a new Promise object for the result
    774  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    775  if (NS_WARN_IF(aRv.Failed())) {
    776    return nullptr;
    777  }
    778 
    779  // Receive the message
    780  mMLS->mTransactionChild->SendRequestReceive(mClientId, message)
    781      ->Then(
    782          GetCurrentSerialEventTarget(), __func__,
    783          [promise, self = RefPtr<MLSGroupView>(this)](GkReceived&& received) {
    784            // Check if the Maybe contains a value
    785            if (received.tag == GkReceived::Tag::None) {
    786              promise->MaybeReject(NS_ERROR_FAILURE);
    787              return;
    788            }
    789 
    790            // Get the context from the GlobalObject
    791            AutoJSAPI jsapi;
    792            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    793              promise->MaybeReject(NS_ERROR_FAILURE);
    794              return;
    795            }
    796            JSContext* cx = jsapi.cx();
    797 
    798            // Construct the Uint8Array objects based on the tag
    799            ErrorResult error;
    800            JS::Rooted<JSObject*> jsGroupId(
    801                cx, Uint8Array::Create(cx, self->mGroupId, error));
    802            error.WouldReportJSException();
    803            if (error.Failed()) {
    804              promise->MaybeReject(std::move(error));
    805              return;
    806            }
    807 
    808            // Initialize the Received dictionary
    809            RootedDictionary<MLSReceived> rvalue(cx);
    810            rvalue.mGroupId.Init(jsGroupId);
    811 
    812            // Populate the Received object based on the tag
    813            switch (received.tag) {
    814              case GkReceived::Tag::GroupIdEpoch: {
    815                MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    816                        ("Processing GroupIdEpoch"));
    817 
    818                JS::Rooted<JSObject*> jsGroupEpoch(
    819                    cx, Uint8Array::Create(
    820                            cx, received.group_id_epoch._0.group_epoch, error));
    821                error.WouldReportJSException();
    822                if (error.Failed()) {
    823                  promise->MaybeReject(std::move(error));
    824                  return;
    825                }
    826 
    827                // Populate the Received object
    828                rvalue.mType = MLSObjectType::Commit_processed;
    829                rvalue.mGroupEpoch.Construct();
    830                rvalue.mGroupEpoch.Value().Init(jsGroupEpoch);
    831                break;
    832              }
    833              case GkReceived::Tag::ApplicationMessage: {
    834                MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    835                        ("Processing ApplicationMessage"));
    836 
    837                JS::Rooted<JSObject*> jsApplicationMessage(
    838                    cx, Uint8Array::Create(cx, received.application_message._0,
    839                                           error));
    840                error.WouldReportJSException();
    841                if (error.Failed()) {
    842                  promise->MaybeReject(std::move(error));
    843                  return;
    844                }
    845 
    846                // Populate the Received object
    847                rvalue.mType = MLSObjectType::Application_message_plaintext;
    848                rvalue.mContent.Construct();
    849                rvalue.mContent.Value().Init(jsApplicationMessage);
    850 
    851                break;
    852              }
    853              case GkReceived::Tag::CommitOutput: {
    854                MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    855                        ("Processing CommitOutput"));
    856 
    857                JS::Rooted<JSObject*> jsClientId(
    858                    cx, Uint8Array::Create(
    859                            cx, received.commit_output._0.identity, error));
    860                error.WouldReportJSException();
    861                if (error.Failed()) {
    862                  promise->MaybeReject(std::move(error));
    863                  return;
    864                }
    865                JS::Rooted<JSObject*> jsCommit(
    866                    cx, Uint8Array::Create(cx, received.commit_output._0.commit,
    867                                           error));
    868                error.WouldReportJSException();
    869                if (error.Failed()) {
    870                  promise->MaybeReject(std::move(error));
    871                  return;
    872                }
    873                JS::Rooted<JSObject*> jsWelcome(
    874                    cx, Uint8Array::Create(
    875                            cx, received.commit_output._0.welcome, error));
    876                error.WouldReportJSException();
    877                if (error.Failed()) {
    878                  promise->MaybeReject(std::move(error));
    879                  return;
    880                }
    881                JS::Rooted<JSObject*> jsGroupInfo(
    882                    cx, Uint8Array::Create(
    883                            cx, received.commit_output._0.group_info, error));
    884                error.WouldReportJSException();
    885                if (error.Failed()) {
    886                  promise->MaybeReject(std::move(error));
    887                  return;
    888                }
    889                JS::Rooted<JSObject*> jsRatchetTree(
    890                    cx, Uint8Array::Create(
    891                            cx, received.commit_output._0.ratchet_tree, error));
    892                error.WouldReportJSException();
    893                if (error.Failed()) {
    894                  promise->MaybeReject(std::move(error));
    895                  return;
    896                }
    897 
    898                // Construct MLSCommitOutput with the parsed data
    899                rvalue.mType = MLSObjectType::Commit_output;
    900                rvalue.mGroupId.Init(jsGroupId);
    901                rvalue.mCommitOutput.Construct();
    902                rvalue.mCommitOutput.Value().mType =
    903                    MLSObjectType::Commit_output;
    904                rvalue.mCommitOutput.Value().mCommit.Init(jsCommit);
    905                rvalue.mCommitOutput.Value().mGroupId.Init(jsGroupId);
    906                if (!received.commit_output._0.welcome.IsEmpty()) {
    907                  rvalue.mCommitOutput.Value().mWelcome.Construct();
    908                  rvalue.mCommitOutput.Value().mWelcome.Value().Init(jsWelcome);
    909                }
    910                if (!received.commit_output._0.group_info.IsEmpty()) {
    911                  rvalue.mCommitOutput.Value().mGroupInfo.Construct();
    912                  rvalue.mCommitOutput.Value().mGroupInfo.Value().Init(
    913                      jsGroupInfo);
    914                }
    915                if (!received.commit_output._0.ratchet_tree.IsEmpty()) {
    916                  rvalue.mCommitOutput.Value().mRatchetTree.Construct();
    917                  rvalue.mCommitOutput.Value().mRatchetTree.Value().Init(
    918                      jsRatchetTree);
    919                }
    920                if (!received.commit_output._0.identity.IsEmpty()) {
    921                  rvalue.mCommitOutput.Value().mClientId.Construct();
    922                  rvalue.mCommitOutput.Value().mClientId.Value().Init(
    923                      jsClientId);
    924                }
    925 
    926                MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    927                        ("Finished processing CommitOutput"));
    928                break;
    929              }
    930              default:
    931                MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    932                        ("Unhandled tag in received data"));
    933                promise->MaybeRejectWithUnknownError(
    934                    "Unhandled tag in received data");
    935                return;
    936            }
    937 
    938            MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    939                    ("Successfully constructed MLSReceived"));
    940 
    941            // Resolve the promise
    942            promise->MaybeResolve(rvalue);
    943          },
    944          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    945            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    946                    ("IPC call rejected with reason: %d",
    947                     static_cast<int>(aReason)));
    948            promise->MaybeRejectWithUnknownError("Failed to receive message");
    949          });
    950 
    951  return promise.forget();
    952 }
    953 
    954 already_AddRefed<Promise> MLSGroupView::HasPendingProposals(ErrorResult& aRv) {
    955  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    956          ("MLSGroupView::HasPendingProposals()"));
    957 
    958  // Create a new Promise object for the result
    959  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
    960  if (NS_WARN_IF(aRv.Failed())) {
    961    return nullptr;
    962  }
    963 
    964  // Receive the message
    965  mMLS->mTransactionChild->SendRequestHasPendingProposals(mGroupId, mClientId)
    966      ->Then(
    967          GetCurrentSerialEventTarget(), __func__,
    968          [promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
    969            // Get the context from the GlobalObject
    970            AutoJSAPI jsapi;
    971            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
    972              MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    973                      ("Failed to initialize JSAPI"));
    974              promise->MaybeRejectWithUnknownError(
    975                  "Failed to initialize JSAPI");
    976              return;
    977            }
    978 
    979            // Resolve the promise directly with the boolean value
    980            promise->MaybeResolve(received);
    981          },
    982          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
    983            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
    984                    ("IPC call rejected with reason: %d",
    985                     static_cast<int>(aReason)));
    986            promise->MaybeRejectWithUnknownError(
    987                "Failed to determine if there are pending proposals");
    988          });
    989 
    990  return promise.forget();
    991 }
    992 
    993 already_AddRefed<Promise> MLSGroupView::ClearPendingProposals(
    994    ErrorResult& aRv) {
    995  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
    996          ("MLSGroupView::ClearPendingProposals()"));
    997 
    998  // Create a new Promise object for the result
    999  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
   1000  if (NS_WARN_IF(aRv.Failed())) {
   1001    return nullptr;
   1002  }
   1003 
   1004  // Receive the message
   1005  mMLS->mTransactionChild->SendRequestClearPendingProposals(mGroupId, mClientId)
   1006      ->Then(
   1007          GetCurrentSerialEventTarget(), __func__,
   1008          [promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
   1009            // Get the context from the GlobalObject
   1010            AutoJSAPI jsapi;
   1011            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
   1012              MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1013                      ("Failed to initialize JSAPI"));
   1014              promise->MaybeRejectWithUnknownError(
   1015                  "Failed to initialize JSAPI");
   1016              return;
   1017            }
   1018 
   1019            // Resolve the promise directly with the boolean value
   1020            promise->MaybeResolve(received);
   1021          },
   1022          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
   1023            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1024                    ("IPC call rejected with reason: %d",
   1025                     static_cast<int>(aReason)));
   1026            promise->MaybeRejectWithUnknownError(
   1027                "Failed to clear pending proposals");
   1028          });
   1029 
   1030  return promise.forget();
   1031 }
   1032 
   1033 already_AddRefed<Promise> MLSGroupView::HasPendingCommit(ErrorResult& aRv) {
   1034  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
   1035          ("MLSGroupView::HasPendingCommit()"));
   1036 
   1037  // Create a new Promise object for the result
   1038  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
   1039  if (NS_WARN_IF(aRv.Failed())) {
   1040    return nullptr;
   1041  }
   1042 
   1043  // Receive the message
   1044  mMLS->mTransactionChild->SendRequestHasPendingCommit(mGroupId, mClientId)
   1045      ->Then(
   1046          GetCurrentSerialEventTarget(), __func__,
   1047          [promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
   1048            // Get the context from the GlobalObject
   1049            AutoJSAPI jsapi;
   1050            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
   1051              MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1052                      ("Failed to initialize JSAPI"));
   1053              promise->MaybeRejectWithUnknownError(
   1054                  "Failed to initialize JSAPI");
   1055              return;
   1056            }
   1057 
   1058            // Resolve the promise directly with the boolean value
   1059            promise->MaybeResolve(received);
   1060          },
   1061          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
   1062            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1063                    ("IPC call rejected with reason: %d",
   1064                     static_cast<int>(aReason)));
   1065            promise->MaybeRejectWithUnknownError(
   1066                "Failed to determine if there is a pending commit");
   1067          });
   1068 
   1069  return promise.forget();
   1070 }
   1071 
   1072 already_AddRefed<Promise> MLSGroupView::ClearPendingCommit(ErrorResult& aRv) {
   1073  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
   1074          ("MLSGroupView::ClearPendingCommit()"));
   1075 
   1076  // Create a new Promise object for the result
   1077  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
   1078  if (NS_WARN_IF(aRv.Failed())) {
   1079    return nullptr;
   1080  }
   1081 
   1082  // Receive the message
   1083  mMLS->mTransactionChild->SendRequestClearPendingCommit(mGroupId, mClientId)
   1084      ->Then(
   1085          GetCurrentSerialEventTarget(), __func__,
   1086          [promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
   1087            // Get the context from the GlobalObject
   1088            AutoJSAPI jsapi;
   1089            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
   1090              MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1091                      ("Failed to initialize JSAPI"));
   1092              promise->MaybeRejectWithUnknownError(
   1093                  "Failed to initialize JSAPI");
   1094              return;
   1095            }
   1096 
   1097            // Resolve the promise directly with the boolean value
   1098            promise->MaybeResolve(received);
   1099          },
   1100          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
   1101            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1102                    ("IPC call rejected with reason: %d",
   1103                     static_cast<int>(aReason)));
   1104            promise->MaybeRejectWithUnknownError(
   1105                "Failed to clear pending commit");
   1106          });
   1107 
   1108  return promise.forget();
   1109 }
   1110 
   1111 already_AddRefed<Promise> MLSGroupView::ApplyPendingCommit(ErrorResult& aRv) {
   1112  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
   1113          ("MLSGroupView::ApplyPendingCommit()"));
   1114 
   1115  // Create a new Promise object for the result
   1116  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
   1117  if (NS_WARN_IF(aRv.Failed())) {
   1118    return nullptr;
   1119  }
   1120 
   1121  // Receive the message
   1122  mMLS->mTransactionChild->SendRequestApplyPendingCommit(mGroupId, mClientId)
   1123      ->Then(
   1124          GetCurrentSerialEventTarget(), __func__,
   1125          [promise, self = RefPtr<MLSGroupView>(this)](GkReceived&& received) {
   1126            // Check if the Maybe contains a value
   1127            if (received.tag == GkReceived::Tag::None) {
   1128              promise->MaybeRejectWithUnknownError(
   1129                  "Failed to apply pending commit");
   1130              return;
   1131            }
   1132 
   1133            // Get the context from the GlobalObject
   1134            AutoJSAPI jsapi;
   1135            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
   1136              MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1137                      ("Failed to initialize JSAPI"));
   1138              promise->MaybeRejectWithUnknownError(
   1139                  "Failed to initialize JSAPI");
   1140              return;
   1141            }
   1142            JSContext* cx = jsapi.cx();
   1143 
   1144            // Construct the Uint8Array objects based on the tag
   1145            ErrorResult error;
   1146            JS::Rooted<JSObject*> jsGroupId(
   1147                cx, Uint8Array::Create(cx, self->mGroupId, error));
   1148            error.WouldReportJSException();
   1149            if (error.Failed()) {
   1150              promise->MaybeReject(std::move(error));
   1151              return;
   1152            }
   1153 
   1154            // Initialize the Received dictionary
   1155            RootedDictionary<MLSReceived> rvalue(cx);
   1156            rvalue.mGroupId.Init(jsGroupId);
   1157 
   1158            // Populate the Received object based on the tag
   1159            switch (received.tag) {
   1160              case GkReceived::Tag::GroupIdEpoch: {
   1161                JS::Rooted<JSObject*> jsGroupEpoch(
   1162                    cx, Uint8Array::Create(
   1163                            cx, received.group_id_epoch._0.group_epoch, error));
   1164                error.WouldReportJSException();
   1165                if (error.Failed()) {
   1166                  promise->MaybeReject(std::move(error));
   1167                  return;
   1168                }
   1169 
   1170                // Populate the Received object
   1171                rvalue.mType = MLSObjectType::Commit_processed;
   1172                rvalue.mGroupEpoch.Construct();
   1173                rvalue.mGroupEpoch.Value().Init(jsGroupEpoch);
   1174                break;
   1175              }
   1176              default:
   1177                MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1178                        ("Unhandled tag in received data"));
   1179                promise->MaybeRejectWithUnknownError(
   1180                    "Unhandled tag in received data");
   1181                return;
   1182            }
   1183 
   1184            MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
   1185                    ("Successfully constructed MLSReceived"));
   1186 
   1187            // Resolve the promise
   1188            promise->MaybeResolve(rvalue);
   1189          },
   1190          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
   1191            MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
   1192                    ("IPC call rejected with reason: %d",
   1193                     static_cast<int>(aReason)));
   1194            promise->MaybeRejectWithUnknownError(
   1195                "Failed to apply pending commit");
   1196          });
   1197 
   1198  return promise.forget();
   1199 }
   1200 
   1201 already_AddRefed<Promise> MLSGroupView::ExportSecret(
   1202    const MLSBytesOrUint8ArrayOrUTF8String& aJsLabel,
   1203    const MLSBytesOrUint8Array& aJsContext, const uint64_t aLen,
   1204    ErrorResult& aRv) {
   1205  MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSGroupView::ExportSecret()"));
   1206 
   1207  // Handle the label parameter
   1208  nsTArray<uint8_t> label = ExtractMLSBytesOrUint8ArrayOrUTF8String(
   1209      MLSObjectType::Exporter_label, aJsLabel, aRv);
   1210  if (NS_WARN_IF(aRv.Failed())) {
   1211    return nullptr;
   1212  }
   1213 
   1214  // We allow the context to be empty
   1215  if (NS_WARN_IF(label.IsEmpty())) {
   1216    aRv.ThrowTypeError("The label must not be empty");
   1217    return nullptr;
   1218  }
   1219 
   1220  // Handle the context parameter
   1221  // Note: we allow the context to be empty
   1222  nsTArray<uint8_t> context = ExtractMLSBytesOrUint8Array(
   1223      MLSObjectType::Exporter_context, aJsContext, aRv);
   1224  if (NS_WARN_IF(aRv.Failed())) {
   1225    return nullptr;
   1226  }
   1227 
   1228  // Create a new Promise object for the result
   1229  RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
   1230  if (NS_WARN_IF(aRv.Failed())) {
   1231    return nullptr;
   1232  }
   1233 
   1234  mMLS->mTransactionChild
   1235      ->SendRequestExportSecret(mGroupId, mClientId, label, context, aLen)
   1236      ->Then(
   1237          GetCurrentSerialEventTarget(), __func__,
   1238          [promise, self = RefPtr<MLSGroupView>(this)](
   1239              Maybe<mozilla::security::mls::GkExporterOutput>&&
   1240                  exporterOutput) {
   1241            // Check if the Maybe contains a value
   1242            if (exporterOutput.isNothing()) {
   1243              promise->MaybeReject(NS_ERROR_FAILURE);
   1244              return;
   1245            }
   1246 
   1247            // Get the context from the GlobalObject
   1248            AutoJSAPI jsapi;
   1249            if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
   1250              promise->MaybeRejectWithUnknownError(
   1251                  "Failed to initialize JSAPI");
   1252              return;
   1253            }
   1254            JSContext* cx = jsapi.cx();
   1255 
   1256            // Construct the Uint8Array objects
   1257            ErrorResult error;
   1258            JS::Rooted<JSObject*> jsGroupId(
   1259                cx, Uint8Array::Create(cx, exporterOutput->group_id, error));
   1260            error.WouldReportJSException();
   1261            if (error.Failed()) {
   1262              promise->MaybeReject(std::move(error));
   1263              return;
   1264            }
   1265            JS::Rooted<JSObject*> jsGroupEpoch(
   1266                cx, Uint8Array::Create(cx, exporterOutput->group_epoch, error));
   1267            error.WouldReportJSException();
   1268            if (error.Failed()) {
   1269              promise->MaybeReject(std::move(error));
   1270              return;
   1271            }
   1272            JS::Rooted<JSObject*> jsLabel(
   1273                cx, Uint8Array::Create(cx, exporterOutput->label, error));
   1274            error.WouldReportJSException();
   1275            if (error.Failed()) {
   1276              promise->MaybeReject(std::move(error));
   1277              return;
   1278            }
   1279            JS::Rooted<JSObject*> jsContext(
   1280                cx, Uint8Array::Create(cx, exporterOutput->context, error));
   1281            error.WouldReportJSException();
   1282            if (error.Failed()) {
   1283              promise->MaybeReject(std::move(error));
   1284              return;
   1285            }
   1286            JS::Rooted<JSObject*> jsExporter(
   1287                cx, Uint8Array::Create(cx, exporterOutput->exporter, error));
   1288            error.WouldReportJSException();
   1289            if (error.Failed()) {
   1290              promise->MaybeReject(std::move(error));
   1291              return;
   1292            }
   1293 
   1294            // Construct MLSBytes with the group identifier as content
   1295            RootedDictionary<MLSExporterOutput> rvalue(cx);
   1296            rvalue.mType = MLSObjectType::Exporter_output;
   1297            rvalue.mGroupId.Init(jsGroupId);
   1298            rvalue.mGroupEpoch.Init(jsGroupEpoch);
   1299            rvalue.mLabel.Init(jsLabel);
   1300            rvalue.mContext.Init(jsContext);
   1301            rvalue.mSecret.Init(jsExporter);
   1302 
   1303            // Resolve the promise
   1304            promise->MaybeResolve(rvalue);
   1305          },
   1306          [promise](::mozilla::ipc::ResponseRejectReason aReason) {
   1307            promise->MaybeRejectWithUnknownError("Failed to export secret");
   1308          });
   1309 
   1310  return promise.forget();
   1311 }
   1312 
   1313 };  // namespace mozilla::dom