Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / dom / mls / MLS.cpp
blobc052eef4f6773bdbbd23884c732fe41f7bfafb3b
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/. */
7 #include "mozilla/dom/MLS.h"
8 #include "mozilla/dom/MLSGroupView.h"
9 #include "mozilla/dom/TypedArray.h"
10 #include "mozilla/dom/Promise.h"
11 #include "nsTArray.h"
12 #include "nsCOMPtr.h"
13 #include "nsIGlobalObject.h"
14 #include "mozilla/ipc/PBackgroundChild.h"
15 #include "mozilla/ipc/BackgroundChild.h"
16 #include "mozilla/dom/MLSTransactionChild.h"
17 #include "mozilla/dom/MLSTransactionMessage.h"
18 #include "mozilla/dom/PMLSTransaction.h"
19 #include "mozilla/ipc/Endpoint.h"
20 #include "mozilla/BasePrincipal.h"
21 #include "MLSGroupView.h"
22 #include "nsTArray.h"
23 #include "mozilla/Logging.h"
24 #include "mozilla/Span.h"
25 #include "nsDebug.h"
26 #include "MLSLogging.h"
27 #include "MLSTypeUtils.h"
29 namespace mozilla::dom {
31 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MLS, mGlobalObject)
33 NS_IMPL_CYCLE_COLLECTING_ADDREF(MLS)
34 NS_IMPL_CYCLE_COLLECTING_RELEASE(MLS)
36 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MLS)
37 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
38 NS_INTERFACE_MAP_ENTRY(nsISupports)
39 NS_INTERFACE_MAP_END
41 // Setup logging
42 mozilla::LazyLogModule gMlsLog("MLS");
44 /* static */ already_AddRefed<MLS> MLS::Constructor(GlobalObject& aGlobalObject,
45 ErrorResult& aRv) {
46 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::Constructor()"));
48 nsCOMPtr<nsIGlobalObject> global(
49 do_QueryInterface(aGlobalObject.GetAsSupports()));
50 if (NS_WARN_IF(!global)) {
51 aRv.Throw(NS_ERROR_FAILURE);
52 return nullptr;
55 // Get the principal and perform some validation on it.
56 // We do not allow MLS in Private Browsing Mode for now.
57 nsIPrincipal* principal = global->PrincipalOrNull();
58 if (!principal || !principal->GetIsContentPrincipal() ||
59 principal->GetIsInPrivateBrowsing()) {
60 aRv.ThrowSecurityError("Cannot create MLS store for origin");
61 return nullptr;
64 // Create the endpoints for the MLS actor
65 mozilla::ipc::Endpoint<PMLSTransactionParent> parentEndpoint;
66 mozilla::ipc::Endpoint<PMLSTransactionChild> childEndpoint;
67 MOZ_ALWAYS_SUCCEEDS(
68 PMLSTransaction::CreateEndpoints(&parentEndpoint, &childEndpoint));
70 mozilla::ipc::PBackgroundChild* backgroundChild =
71 mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
72 if (!backgroundChild) {
73 aRv.Throw(NS_ERROR_UNEXPECTED);
74 return nullptr;
77 // Bind the child actor, and send the parent endpoint.
78 RefPtr<MLSTransactionChild> actor = new MLSTransactionChild();
79 MOZ_ALWAYS_TRUE(childEndpoint.Bind(actor));
81 MOZ_ALWAYS_TRUE(backgroundChild->SendCreateMLSTransaction(
82 std::move(parentEndpoint), WrapNotNull(principal)));
84 return MakeAndAddRef<MLS>(global, actor);
87 MLS::MLS(nsIGlobalObject* aGlobalObject, MLSTransactionChild* aActor)
88 : mGlobalObject(aGlobalObject), mTransactionChild(aActor) {
89 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::MLS()"));
92 MLS::~MLS() {
93 if (mTransactionChild) {
94 mTransactionChild->Close();
98 JSObject* MLS::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
99 return MLS_Binding::Wrap(aCx, this, aGivenProto);
103 // API
106 already_AddRefed<Promise> MLS::DeleteState(ErrorResult& aRv) {
107 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::DeleteState()"));
109 // Create a new Promise object for the result
110 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
111 if (NS_WARN_IF(aRv.Failed())) {
112 return nullptr;
115 mTransactionChild->SendRequestStateDelete(
116 [promise](bool result) {
117 if (result) {
118 promise->MaybeResolveWithUndefined();
119 } else {
120 promise->MaybeReject(NS_ERROR_FAILURE);
123 [promise](::mozilla::ipc::ResponseRejectReason) {
124 promise->MaybeRejectWithUnknownError("deleteState failed");
127 return promise.forget();
130 already_AddRefed<Promise> MLS::GenerateIdentity(ErrorResult& aRv) {
131 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GenerateIdentity()"));
133 // Create a new Promise object for the result
134 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
135 if (NS_WARN_IF(aRv.Failed())) {
136 return nullptr;
139 mTransactionChild->SendRequestGenerateIdentityKeypair()->Then(
140 GetCurrentSerialEventTarget(), __func__,
141 [promise, self = RefPtr{this}](Maybe<RawBytes>&& result) {
142 // Check if the value is Nothing
143 if (result.isNothing()) {
144 promise->MaybeRejectWithUnknownError(
145 "generateIdentityKeypair failed");
146 return;
149 // Get the context from the GlobalObject
150 AutoJSAPI jsapi;
151 if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
152 promise->MaybeRejectWithUnknownError(
153 "generateIdentityKeypair failed");
154 return;
156 JSContext* cx = jsapi.cx();
158 // Construct the Uint8Array object
159 ErrorResult error;
160 JS::Rooted<JSObject*> content(
161 cx, Uint8Array::Create(cx, result->data(), error));
162 error.WouldReportJSException();
163 if (error.Failed()) {
164 promise->MaybeReject(std::move(error));
165 return;
168 // Construct MLSBytes with the client identifer as content
169 RootedDictionary<MLSBytes> rvalue(cx);
170 rvalue.mType = MLSObjectType::Client_identifier;
171 rvalue.mContent.Init(content);
173 // Resolve the promise with the MLSBytes object
174 promise->MaybeResolve(rvalue);
176 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
177 promise->MaybeRejectWithUnknownError("generateIdentity failed");
180 return promise.forget();
183 already_AddRefed<Promise> MLS::GenerateCredential(
184 const MLSBytesOrUint8ArrayOrUTF8String& aJsCredContent, ErrorResult& aRv) {
185 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
186 ("MLS::GenerateCredentialBasic()"));
188 // Handle the credential content parameter
189 nsTArray<uint8_t> credContent = ExtractMLSBytesOrUint8ArrayOrUTF8String(
190 MLSObjectType::Credential_basic, aJsCredContent, aRv);
191 if (NS_WARN_IF(aRv.Failed())) {
192 return nullptr;
195 // Check if the credContent is empty
196 if (NS_WARN_IF(credContent.IsEmpty())) {
197 aRv.ThrowTypeError("The credential content must not be empty");
198 return nullptr;
201 // Create a new Promise object for the result
202 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
203 if (NS_WARN_IF(aRv.Failed())) {
204 return nullptr;
207 mTransactionChild->SendRequestGenerateCredentialBasic(credContent)
208 ->Then(
209 GetCurrentSerialEventTarget(), __func__,
210 [promise, self = RefPtr{this}](Maybe<RawBytes>&& result) {
211 // Check if the value is Nothing
212 if (result.isNothing()) {
213 promise->MaybeRejectWithUnknownError(
214 "generateCredentialBasic failed");
215 return;
218 // Get the context from the GlobalObject
219 AutoJSAPI jsapi;
220 if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
221 promise->MaybeRejectWithUnknownError(
222 "generateCredentialBasic failed");
223 return;
225 JSContext* cx = jsapi.cx();
227 // Construct the Uint8Array object
228 ErrorResult error;
229 JS::Rooted<JSObject*> content(
230 cx, Uint8Array::Create(cx, result->data(), error));
231 error.WouldReportJSException();
232 if (error.Failed()) {
233 promise->MaybeReject(std::move(error));
234 return;
237 // Construct MLSBytes with the client identifer as content
238 RootedDictionary<MLSBytes> rvalue(cx);
239 rvalue.mType = MLSObjectType::Credential_basic;
240 rvalue.mContent.Init(content);
242 // Resolve the promise
243 promise->MaybeResolve(rvalue);
245 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
246 promise->MaybeRejectWithUnknownError(
247 "generateCredentialBasic failed");
250 return promise.forget();
253 already_AddRefed<Promise> MLS::GenerateKeyPackage(
254 const MLSBytesOrUint8Array& aJsClientIdentifier,
255 const MLSBytesOrUint8Array& aJsCredential, ErrorResult& aRv) {
256 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GenerateKeyPackage()"));
258 // Handle the client identifier parameter
259 nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
260 MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
261 if (NS_WARN_IF(aRv.Failed())) {
262 return nullptr;
265 // Check if the client identifier is empty
266 if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
267 aRv.ThrowTypeError("The client identifier must not be empty");
268 return nullptr;
271 // Handle the credential parameter
272 nsTArray<uint8_t> credential = ExtractMLSBytesOrUint8Array(
273 MLSObjectType::Credential_basic, aJsCredential, aRv);
274 if (NS_WARN_IF(aRv.Failed())) {
275 return nullptr;
278 // Check if the credential is empty
279 if (NS_WARN_IF(credential.IsEmpty())) {
280 aRv.ThrowTypeError("The credential must not be empty");
281 return nullptr;
284 // Create a new Promise object for the result
285 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
286 if (NS_WARN_IF(aRv.Failed())) {
287 return nullptr;
290 // Use the static method or instance to send the IPC message
291 mTransactionChild->SendRequestGenerateKeyPackage(clientIdentifier, credential)
292 ->Then(
293 GetCurrentSerialEventTarget(), __func__,
294 [promise, self = RefPtr{this}](Maybe<RawBytes>&& keyPackage) {
295 // Check if the value is Nothing
296 if (keyPackage.isNothing()) {
297 promise->MaybeReject(NS_ERROR_FAILURE);
298 return;
301 // Get the context from the GlobalObject
302 AutoJSAPI jsapi;
303 if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
304 promise->MaybeReject(NS_ERROR_FAILURE);
305 return;
307 JSContext* cx = jsapi.cx();
309 // Construct the Uint8Array object
310 ErrorResult error;
311 JS::Rooted<JSObject*> content(
312 cx, Uint8Array::Create(cx, keyPackage->data(), error));
313 error.WouldReportJSException();
314 if (error.Failed()) {
315 promise->MaybeReject(std::move(error));
316 return;
319 // Construct MLSBytes with the client identifer as content
320 RootedDictionary<MLSBytes> rvalue(cx);
321 rvalue.mType = MLSObjectType::Key_package;
322 rvalue.mContent.Init(content);
324 // Resolve the promise
325 promise->MaybeResolve(rvalue);
327 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
328 promise->MaybeRejectWithUnknownError("generateKeyPackage failed");
331 return promise.forget();
334 already_AddRefed<Promise> MLS::GroupCreate(
335 const MLSBytesOrUint8Array& aJsClientIdentifier,
336 const MLSBytesOrUint8Array& aJsCredential, ErrorResult& aRv) {
337 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupCreate()"));
339 // Handle the client identifier parameter
340 nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
341 MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
342 if (NS_WARN_IF(aRv.Failed())) {
343 return nullptr;
346 // Check if the client identifier is empty
347 if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
348 aRv.ThrowTypeError("The client identifier must not be empty");
349 return nullptr;
352 // Handle the credential parameter
353 nsTArray<uint8_t> credential = ExtractMLSBytesOrUint8Array(
354 MLSObjectType::Credential_basic, aJsCredential, aRv);
355 if (NS_WARN_IF(aRv.Failed())) {
356 return nullptr;
359 // Check if the credential is empty
360 if (NS_WARN_IF(credential.IsEmpty())) {
361 aRv.ThrowTypeError("The credential must not be empty");
362 return nullptr;
365 // Log the hex of clientIdentifier
366 if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
367 nsAutoCString clientIdHex;
368 for (uint8_t byte : clientIdentifier) {
369 clientIdHex.AppendPrintf("%02X", byte);
371 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
372 ("clientIdentifier in hex: %s\n", clientIdHex.get()));
375 // Initialize jsGroupIdentifier to one byte of value 0xFF.
376 // We do not want to allow choosing the GID at this point.
377 // This value not being of the correct length will be discarded
378 // internally and a fresh GID will be generated.
380 // In the future, the caller will allow choosing the GID.
381 AutoTArray<uint8_t, 1> groupIdentifier{0xFF};
383 // Create a new Promise object for the result
384 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
385 if (NS_WARN_IF(aRv.Failed())) {
386 return nullptr;
389 // Use the static method or instance to send the IPC message
390 mTransactionChild
391 ->SendRequestGroupCreate(clientIdentifier, credential, groupIdentifier)
392 ->Then(
393 GetCurrentSerialEventTarget(), __func__,
394 [promise, self = RefPtr{this},
395 clientIdentifier(std::move(clientIdentifier))](
396 Maybe<mozilla::security::mls::GkGroupIdEpoch>&&
397 groupIdEpoch) mutable {
398 // Check if the value is Nothing
399 if (groupIdEpoch.isNothing()) {
400 promise->MaybeReject(NS_ERROR_FAILURE);
401 return;
404 RefPtr<MLSGroupView> group =
405 new MLSGroupView(self, std::move(groupIdEpoch->group_id),
406 std::move(clientIdentifier));
408 promise->MaybeResolve(group);
410 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
411 MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
412 ("IPC message rejected with reason: %d",
413 static_cast<int>(aReason)));
414 promise->MaybeRejectWithUnknownError("groupCreate failed");
417 return promise.forget();
420 already_AddRefed<mozilla::dom::Promise> MLS::GroupGet(
421 const MLSBytesOrUint8Array& aJsGroupIdentifier,
422 const MLSBytesOrUint8Array& aJsClientIdentifier, ErrorResult& aRv) {
423 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupGet()"));
425 // Handle the group identifier parameter
426 nsTArray<uint8_t> groupIdentifier = ExtractMLSBytesOrUint8Array(
427 MLSObjectType::Group_identifier, aJsGroupIdentifier, aRv);
428 if (NS_WARN_IF(aRv.Failed())) {
429 return nullptr;
432 // Check if the group identifier is empty
433 if (NS_WARN_IF(groupIdentifier.IsEmpty())) {
434 aRv.ThrowTypeError("The group identifier must not be empty");
435 return nullptr;
438 // Handle the client identifier parameter
439 nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
440 MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
441 if (NS_WARN_IF(aRv.Failed())) {
442 return nullptr;
445 // Check if the client identifier is empty
446 if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
447 aRv.ThrowTypeError("The client identifier must not be empty");
448 return nullptr;
451 // Create a new Promise object for the result
452 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
453 if (NS_WARN_IF(aRv.Failed())) {
454 return nullptr;
457 // Initialize label, context and len
458 // We pass this through IPC to be able to reuse the same code for different
459 // labels in the future
460 AutoTArray<uint8_t, 7> label{'l', 'i', 'v', 'e', 'n', 'e', 's', 's'};
461 AutoTArray<uint8_t, 1> context{0x00};
462 uint64_t len = 32;
464 // Use the static method or instance to send the IPC message
465 mTransactionChild
466 ->SendRequestExportSecret(groupIdentifier, clientIdentifier, label,
467 context, len)
468 ->Then(
469 GetCurrentSerialEventTarget(), __func__,
470 [promise, self = RefPtr{this},
471 groupIdentifier(std::move(groupIdentifier)),
472 clientIdentifier(std::move(clientIdentifier))](
473 Maybe<mozilla::security::mls::GkExporterOutput>&&
474 exporterOutput) mutable {
475 // Check if the exporterOutput contains a value
476 if (exporterOutput.isNothing()) {
477 promise->MaybeReject(NS_ERROR_FAILURE);
478 return;
481 RefPtr<MLSGroupView> group =
482 new MLSGroupView(self, std::move(exporterOutput->group_id),
483 std::move(clientIdentifier));
484 promise->MaybeResolve(group);
486 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
487 promise->MaybeRejectWithUnknownError("exportSecret failed");
490 return promise.forget();
493 already_AddRefed<Promise> MLS::GroupJoin(
494 const MLSBytesOrUint8Array& aJsClientIdentifier,
495 const MLSBytesOrUint8Array& aJsWelcome, ErrorResult& aRv) {
496 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GroupJoin()"));
498 // Handle the client identifier parameter
499 nsTArray<uint8_t> clientIdentifier = ExtractMLSBytesOrUint8Array(
500 MLSObjectType::Client_identifier, aJsClientIdentifier, aRv);
501 if (NS_WARN_IF(aRv.Failed())) {
502 return nullptr;
505 // Check if the client identifier is empty
506 if (NS_WARN_IF(clientIdentifier.IsEmpty())) {
507 aRv.ThrowTypeError("The client identifier must not be empty");
508 return nullptr;
511 // Handle the welcome parameter
512 nsTArray<uint8_t> welcome =
513 ExtractMLSBytesOrUint8Array(MLSObjectType::Welcome, aJsWelcome, aRv);
514 if (NS_WARN_IF(aRv.Failed())) {
515 return nullptr;
518 // Check if the welcome is empty
519 if (NS_WARN_IF(welcome.IsEmpty())) {
520 aRv.ThrowTypeError("The welcome must not be empty");
521 return nullptr;
524 // Create a new Promise object for the result
525 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
526 if (NS_WARN_IF(aRv.Failed())) {
527 return nullptr;
530 mTransactionChild->SendRequestGroupJoin(clientIdentifier, welcome)
531 ->Then(
532 GetCurrentSerialEventTarget(), __func__,
533 [promise, self = RefPtr{this},
534 clientIdentifier(std::move(clientIdentifier))](
535 Maybe<mozilla::security::mls::GkGroupIdEpoch>&&
536 groupIdEpoch) mutable {
537 // Check if the value is Nothing
538 if (groupIdEpoch.isNothing()) {
539 promise->MaybeReject(NS_ERROR_FAILURE);
540 return;
543 // Returns groupId and epoch
544 RefPtr<MLSGroupView> group =
545 new MLSGroupView(self, std::move(groupIdEpoch->group_id),
546 std::move(clientIdentifier));
548 // Resolve the promise
549 promise->MaybeResolve(group);
551 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
552 promise->MaybeRejectWithUnknownError("groupJoin failed");
555 return promise.forget();
558 already_AddRefed<Promise> MLS::GetGroupIdFromMessage(
559 const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv) {
560 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLS::GetGroupIdFromMessage()"));
562 // Handle the message parameter
563 nsTArray<uint8_t> message =
564 ExtractMLSBytesOrUint8ArrayWithUnknownType(aJsMessage, aRv);
565 if (NS_WARN_IF(aRv.Failed())) {
566 return nullptr;
569 // Check if the message is empty
570 if (NS_WARN_IF(message.IsEmpty())) {
571 aRv.ThrowTypeError("The message must not be empty");
572 return nullptr;
575 // Create a new Promise object for the result
576 RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
577 if (NS_WARN_IF(aRv.Failed())) {
578 return nullptr;
581 mTransactionChild->SendRequestGetGroupIdentifier(message)->Then(
582 GetCurrentSerialEventTarget(), __func__,
583 [promise, self = RefPtr{this},
584 message(std::move(message))](Maybe<RawBytes>&& result) {
585 // Check if the value is Nothing
586 if (result.isNothing()) {
587 promise->MaybeReject(NS_ERROR_FAILURE);
588 return;
591 // Get the context from the GlobalObject
592 AutoJSAPI jsapi;
593 if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
594 MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
595 ("Failed to initialize JSAPI"));
596 promise->MaybeReject(NS_ERROR_FAILURE);
597 return;
599 JSContext* cx = jsapi.cx();
601 // Construct the Uint8Array objects based on the tag
602 ErrorResult error;
603 JS::Rooted<JSObject*> jsGroupId(
604 cx, Uint8Array::Create(cx, result->data(), error));
605 error.WouldReportJSException();
606 if (error.Failed()) {
607 promise->MaybeReject(std::move(error));
608 return;
611 // Construct the MLSBytes object for the groupId
612 RootedDictionary<MLSBytes> rvalue(cx);
613 rvalue.mType = MLSObjectType::Group_identifier;
614 rvalue.mContent.Init(jsGroupId);
616 // Log if in debug mode
617 if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
618 MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
619 ("Successfully constructed MLSBytes"));
622 // Resolve the promise
623 promise->MaybeResolve(rvalue);
625 [promise](::mozilla::ipc::ResponseRejectReason aReason) {
626 MOZ_LOG(
627 gMlsLog, mozilla::LogLevel::Error,
628 ("IPC call rejected with reason: %d", static_cast<int>(aReason)));
629 promise->MaybeRejectWithUnknownError("getGroupIdFromMessage failed");
632 return promise.forget();
635 } // namespace mozilla::dom