Bug 1863873 - Block ability to perform audio decoding outside of Utility on release...
[gecko.git] / dom / webauthn / MacOSWebAuthnService.mm
blobaa62138441091902d50e700dac68cba73613799f
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 file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #import <AuthenticationServices/AuthenticationServices.h>
9 #include "MacOSWebAuthnService.h"
11 #include "CFTypeRefPtr.h"
12 #include "WebAuthnAutoFillEntry.h"
13 #include "WebAuthnEnumStrings.h"
14 #include "WebAuthnResult.h"
15 #include "WebAuthnTransportIdentifiers.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/StaticPrefs_security.h"
18 #include "mozilla/dom/CanonicalBrowsingContext.h"
19 #include "nsCocoaUtils.h"
20 #include "nsIWebAuthnPromise.h"
21 #include "nsThreadUtils.h"
23 // The documentation for the platform APIs used here can be found at:
24 // https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys
26 namespace {
27 static mozilla::LazyLogModule gMacOSWebAuthnServiceLog("macoswebauthnservice");
28 }  // namespace
30 namespace mozilla::dom {
31 class API_AVAILABLE(macos(13.3)) MacOSWebAuthnService;
32 }  // namespace mozilla::dom
34 // The following ASC* declarations are from the private framework
35 // AuthenticationServicesCore. The full definitions can be found in WebKit's
36 // source at Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h.
37 // Overriding ASAuthorizationController's _requestContextWithRequests is
38 // currently the only way to provide the right information to the macOS
39 // WebAuthn API (namely, the clientDataHash for requests made to physical
40 // tokens).
42 NS_ASSUME_NONNULL_BEGIN
44 @class ASCPublicKeyCredentialDescriptor;
45 @interface ASCPublicKeyCredentialDescriptor : NSObject <NSSecureCoding>
46 - (instancetype)initWithCredentialID:(NSData*)credentialID
47                           transports:
48                               (nullable NSArray<NSString*>*)allowedTransports;
49 @end
51 @protocol ASCPublicKeyCredentialCreationOptions
52 @property(nonatomic, copy) NSData* clientDataHash;
53 @property(nonatomic, nullable, copy) NSData* challenge;
54 @property(nonatomic, copy)
55     NSArray<ASCPublicKeyCredentialDescriptor*>* excludedCredentials;
56 @end
58 @protocol ASCPublicKeyCredentialAssertionOptions <NSCopying>
59 @property(nonatomic, copy) NSData* clientDataHash;
60 @end
62 @protocol ASCCredentialRequestContext
63 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialCreationOptions>
64     platformKeyCredentialCreationOptions;
65 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialAssertionOptions>
66     platformKeyCredentialAssertionOptions;
67 @end
69 @interface ASAuthorizationController (Secrets)
70 - (id<ASCCredentialRequestContext>)
71     _requestContextWithRequests:(NSArray<ASAuthorizationRequest*>*)requests
72                           error:(NSError**)outError;
73 @end
75 NSArray<NSString*>* TransportsByteToTransportsArray(const uint8_t aTransports)
76     API_AVAILABLE(macos(13.3)) {
77   NSMutableArray<NSString*>* transportsNS = [[NSMutableArray alloc] init];
78   if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) ==
79       MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
80     [transportsNS
81         addObject:
82             ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportUSB];
83   }
84   if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) ==
85       MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
86     [transportsNS
87         addObject:
88             ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportNFC];
89   }
90   if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) ==
91       MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
92     [transportsNS
93         addObject:
94             ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportBluetooth];
95   }
96   // TODO (bug 1859367): the platform doesn't have a definition for "internal"
97   // transport. When it does, this code should be updated to handle it.
98   return transportsNS;
101 NSArray* CredentialListsToCredentialDescriptorArray(
102     const nsTArray<nsTArray<uint8_t>>& aCredentialList,
103     const nsTArray<uint8_t>& aCredentialListTransports,
104     const Class credentialDescriptorClass) API_AVAILABLE(macos(13.3)) {
105   MOZ_ASSERT(aCredentialList.Length() == aCredentialListTransports.Length());
106   NSMutableArray* credentials = [[NSMutableArray alloc] init];
107   for (size_t i = 0; i < aCredentialList.Length(); i++) {
108     const nsTArray<uint8_t>& credentialId = aCredentialList[i];
109     const uint8_t& credentialTransports = aCredentialListTransports[i];
110     NSData* credentialIdNS = [NSData dataWithBytes:credentialId.Elements()
111                                             length:credentialId.Length()];
112     NSArray<NSString*>* credentialTransportsNS =
113         TransportsByteToTransportsArray(credentialTransports);
114     NSObject* credential = [[credentialDescriptorClass alloc]
115         initWithCredentialID:credentialIdNS
116                   transports:credentialTransportsNS];
117     [credentials addObject:credential];
118   }
119   return credentials;
122 // MacOSAuthorizationController is an ASAuthorizationController that overrides
123 // _requestContextWithRequests so that the implementation can set some options
124 // that aren't directly settable using the public API.
125 API_AVAILABLE(macos(13.3))
126 @interface MacOSAuthorizationController : ASAuthorizationController
127 @end
129 @implementation MacOSAuthorizationController {
130   nsTArray<uint8_t> mClientDataHash;
131   nsTArray<nsTArray<uint8_t>> mCredentialList;
132   nsTArray<uint8_t> mCredentialListTransports;
135 - (void)stashClientDataHash:(nsTArray<uint8_t>&&)clientDataHash
136               andCredentialList:(nsTArray<nsTArray<uint8_t>>&&)credentialList
137     andCredentialListTransports:(nsTArray<uint8_t>&&)credentialListTransports {
138   mClientDataHash = std::move(clientDataHash);
139   mCredentialList = std::move(credentialList);
140   mCredentialListTransports = std::move(credentialListTransports);
143 - (id<ASCCredentialRequestContext>)
144     _requestContextWithRequests:(NSArray<ASAuthorizationRequest*>*)requests
145                           error:(NSError**)outError {
146   id<ASCCredentialRequestContext> context =
147       [super _requestContextWithRequests:requests error:outError];
149   id<ASCPublicKeyCredentialCreationOptions> registrationOptions =
150       context.platformKeyCredentialCreationOptions;
151   if (registrationOptions) {
152     registrationOptions.clientDataHash =
153         [NSData dataWithBytes:mClientDataHash.Elements()
154                        length:mClientDataHash.Length()];
155     // Unset challenge so that the implementation uses clientDataHash (the API
156     // returns an error otherwise).
157     registrationOptions.challenge = nil;
158     const Class publicKeyCredentialDescriptorClass =
159         NSClassFromString(@"ASCPublicKeyCredentialDescriptor");
160     NSArray<ASCPublicKeyCredentialDescriptor*>* excludedCredentials =
161         CredentialListsToCredentialDescriptorArray(
162             mCredentialList, mCredentialListTransports,
163             publicKeyCredentialDescriptorClass);
164     if ([excludedCredentials count] > 0) {
165       registrationOptions.excludedCredentials = excludedCredentials;
166     }
167   }
169   id<ASCPublicKeyCredentialAssertionOptions> signOptions =
170       context.platformKeyCredentialAssertionOptions;
171   if (signOptions) {
172     signOptions.clientDataHash =
173         [NSData dataWithBytes:mClientDataHash.Elements()
174                        length:mClientDataHash.Length()];
175     context.platformKeyCredentialAssertionOptions =
176         [signOptions copyWithZone:nil];
177   }
179   return context;
181 @end
183 // MacOSAuthenticatorRequestDelegate is an ASAuthorizationControllerDelegate,
184 // which can be set as an ASAuthorizationController's delegate to be called
185 // back when a request for a platform authenticator attestation or assertion
186 // response completes either with an attestation or assertion
187 // (didCompleteWithAuthorization) or with an error (didCompleteWithError).
188 API_AVAILABLE(macos(13.3))
189 @interface MacOSAuthenticatorRequestDelegate
190     : NSObject <ASAuthorizationControllerDelegate>
191 - (void)setCallback:(mozilla::dom::MacOSWebAuthnService*)callback;
192 @end
194 // MacOSAuthenticatorPresentationContextProvider is an
195 // ASAuthorizationControllerPresentationContextProviding, which can be set as
196 // an ASAuthorizationController's presentationContextProvider, and provides a
197 // presentation anchor for the ASAuthorizationController. Basically, this
198 // provides the API a handle to the window that made the request.
199 API_AVAILABLE(macos(13.3))
200 @interface MacOSAuthenticatorPresentationContextProvider
201     : NSObject <ASAuthorizationControllerPresentationContextProviding>
202 @property(nonatomic, strong) NSWindow* window;
203 @end
205 namespace mozilla::dom {
207 #pragma clang diagnostic push
208 #pragma clang diagnostic ignored "-Wnullability-completeness"
209 class API_AVAILABLE(macos(13.3)) MacOSWebAuthnService final
210     : public nsIWebAuthnService {
211  public:
212   MacOSWebAuthnService()
213       : mTransactionState(Nothing(),
214                           "MacOSWebAuthnService::mTransactionState") {}
216   NS_DECL_THREADSAFE_ISUPPORTS
217   NS_DECL_NSIWEBAUTHNSERVICE
219   void FinishMakeCredential(const nsTArray<uint8_t>& aRawAttestationObject,
220                             const nsTArray<uint8_t>& aCredentialId,
221                             const nsTArray<nsString>& aTransports,
222                             const Maybe<nsString>& aAuthenticatorAttachment);
224   void FinishGetAssertion(const nsTArray<uint8_t>& aCredentialId,
225                           const nsTArray<uint8_t>& aSignature,
226                           const nsTArray<uint8_t>& aAuthenticatorData,
227                           const nsTArray<uint8_t>& aUserHandle,
228                           const Maybe<nsString>& aAuthenticatorAttachment);
229   void ReleasePlatformResources();
230   void AbortTransaction(nsresult aError);
232  private:
233   ~MacOSWebAuthnService() = default;
235   void PerformRequests(NSArray<ASAuthorizationRequest*>* aRequests,
236                        nsTArray<uint8_t>&& aClientDataHash,
237                        nsTArray<nsTArray<uint8_t>>&& aCredentialList,
238                        nsTArray<uint8_t>&& aCredentialListTransports,
239                        uint64_t aBrowsingContextId);
241   struct TransactionState {
242     uint64_t transactionId;
243     uint64_t browsingContextId;
244     Maybe<RefPtr<nsIWebAuthnSignArgs>> pendingSignArgs;
245     Maybe<RefPtr<nsIWebAuthnSignPromise>> pendingSignPromise;
246     Maybe<nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>> autoFillEntries;
247   };
249   using TransactionStateMutex = DataMutex<Maybe<TransactionState>>;
250   void DoGetAssertion(Maybe<nsTArray<uint8_t>>&& aSelectedCredentialId,
251                       const TransactionStateMutex::AutoLock& aGuard);
253   TransactionStateMutex mTransactionState;
255   // Main thread only:
256   ASAuthorizationWebBrowserPublicKeyCredentialManager* mCredentialManager = nil;
257   nsCOMPtr<nsIWebAuthnRegisterPromise> mRegisterPromise;
258   nsCOMPtr<nsIWebAuthnSignPromise> mSignPromise;
259   MacOSAuthorizationController* mAuthorizationController = nil;
260   MacOSAuthenticatorRequestDelegate* mRequestDelegate = nil;
261   MacOSAuthenticatorPresentationContextProvider* mPresentationContextProvider =
262       nil;
264 #pragma clang diagnostic pop
266 }  // namespace mozilla::dom
268 nsTArray<uint8_t> NSDataToArray(NSData* data) {
269   nsTArray<uint8_t> array(reinterpret_cast<const uint8_t*>(data.bytes),
270                           data.length);
271   return array;
274 @implementation MacOSAuthenticatorRequestDelegate {
275   RefPtr<mozilla::dom::MacOSWebAuthnService> mCallback;
278 - (void)setCallback:(mozilla::dom::MacOSWebAuthnService*)callback {
279   mCallback = callback;
282 - (void)authorizationController:(ASAuthorizationController*)controller
283     didCompleteWithAuthorization:(ASAuthorization*)authorization {
284   if ([authorization.credential
285           conformsToProtocol:
286               @protocol(ASAuthorizationPublicKeyCredentialRegistration)]) {
287     MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
288             ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
289              "got registration"));
290     id<ASAuthorizationPublicKeyCredentialRegistration> credential =
291         (id<ASAuthorizationPublicKeyCredentialRegistration>)
292             authorization.credential;
293     nsTArray<uint8_t> rawAttestationObject(
294         NSDataToArray(credential.rawAttestationObject));
295     nsTArray<uint8_t> credentialId(NSDataToArray(credential.credentialID));
296     nsTArray<nsString> transports;
297     mozilla::Maybe<nsString> authenticatorAttachment;
298     if ([credential isKindOfClass:
299                         [ASAuthorizationPlatformPublicKeyCredentialRegistration
300                             class]]) {
301       transports.AppendElement(u"internal"_ns);
302 #if defined(MAC_OS_VERSION_13_5) && \
303     MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_5
304       if (__builtin_available(macos 13.5, *)) {
305         ASAuthorizationPlatformPublicKeyCredentialRegistration*
306             platformCredential =
307                 (ASAuthorizationPlatformPublicKeyCredentialRegistration*)
308                     credential;
309         switch (platformCredential.attachment) {
310           case ASAuthorizationPublicKeyCredentialAttachmentCrossPlatform:
311             authenticatorAttachment.emplace(u"cross-platform"_ns);
312             break;
313           case ASAuthorizationPublicKeyCredentialAttachmentPlatform:
314             authenticatorAttachment.emplace(u"platform"_ns);
315             break;
316           default:
317             break;
318         }
319       }
320 #endif
321     } else {
322       authenticatorAttachment.emplace(u"cross-platform"_ns);
323     }
324     mCallback->FinishMakeCredential(rawAttestationObject, credentialId,
325                                     transports, authenticatorAttachment);
326   } else if ([authorization.credential
327                  conformsToProtocol:
328                      @protocol(ASAuthorizationPublicKeyCredentialAssertion)]) {
329     MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
330             ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
331              "got assertion"));
332     id<ASAuthorizationPublicKeyCredentialAssertion> credential =
333         (id<ASAuthorizationPublicKeyCredentialAssertion>)
334             authorization.credential;
335     nsTArray<uint8_t> credentialId(NSDataToArray(credential.credentialID));
336     nsTArray<uint8_t> signature(NSDataToArray(credential.signature));
337     nsTArray<uint8_t> rawAuthenticatorData(
338         NSDataToArray(credential.rawAuthenticatorData));
339     nsTArray<uint8_t> userHandle(NSDataToArray(credential.userID));
340     mozilla::Maybe<nsString> authenticatorAttachment;
341     if ([credential
342             isKindOfClass:[ASAuthorizationPlatformPublicKeyCredentialAssertion
343                               class]]) {
344 #if defined(MAC_OS_VERSION_13_5) && \
345     MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_5
346       if (__builtin_available(macos 13.5, *)) {
347         ASAuthorizationPlatformPublicKeyCredentialAssertion*
348             platformCredential =
349                 (ASAuthorizationPlatformPublicKeyCredentialAssertion*)
350                     credential;
351         switch (platformCredential.attachment) {
352           case ASAuthorizationPublicKeyCredentialAttachmentCrossPlatform:
353             authenticatorAttachment.emplace(u"cross-platform"_ns);
354             break;
355           case ASAuthorizationPublicKeyCredentialAttachmentPlatform:
356             authenticatorAttachment.emplace(u"platform"_ns);
357             break;
358           default:
359             break;
360         }
361       }
362 #endif
363     } else {
364       authenticatorAttachment.emplace(u"cross-platform"_ns);
365     }
366     mCallback->FinishGetAssertion(credentialId, signature, rawAuthenticatorData,
367                                   userHandle, authenticatorAttachment);
368   } else {
369     MOZ_LOG(
370         gMacOSWebAuthnServiceLog, mozilla::LogLevel::Error,
371         ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
372          "authorization.credential is neither registration nor assertion!"));
373     MOZ_ASSERT_UNREACHABLE(
374         "should have ASAuthorizationPublicKeyCredentialRegistration or "
375         "ASAuthorizationPublicKeyCredentialAssertion");
376   }
377   mCallback->ReleasePlatformResources();
378   mCallback = nullptr;
381 - (void)authorizationController:(ASAuthorizationController*)controller
382            didCompleteWithError:(NSError*)error {
383   nsAutoString errorDescription;
384   nsCocoaUtils::GetStringForNSString(error.localizedDescription,
385                                      errorDescription);
386   MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Warning,
387           ("MacOSAuthenticatorRequestDelegate::didCompleteWithError: %ld (%s)",
388            error.code, NS_ConvertUTF16toUTF8(errorDescription).get()));
389   nsresult rv;
390   switch (error.code) {
391     case ASAuthorizationErrorCanceled:
392       rv = NS_ERROR_DOM_ABORT_ERR;
393       break;
394     case ASAuthorizationErrorFailed:
395       // The message is right, but it's not about indexeddb.
396       // See https://webidl.spec.whatwg.org/#constrainterror
397       rv = NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
398       break;
399     case ASAuthorizationErrorUnknown:
400       rv = NS_ERROR_DOM_UNKNOWN_ERR;
401       break;
402     default:
403       rv = NS_ERROR_DOM_NOT_ALLOWED_ERR;
404       break;
405   }
406   mCallback->AbortTransaction(rv);
407   mCallback = nullptr;
409 @end
411 @implementation MacOSAuthenticatorPresentationContextProvider
412 @synthesize window = window;
414 - (ASPresentationAnchor)presentationAnchorForAuthorizationController:
415     (ASAuthorizationController*)controller {
416   return window;
418 @end
420 namespace mozilla::dom {
422 #pragma clang diagnostic push
423 #pragma clang diagnostic ignored "-Wnullability-completeness"
424 // Given a browsingContextId, attempts to determine the NSWindow associated
425 // with that browser.
426 nsresult BrowsingContextIdToNSWindow(uint64_t browsingContextId,
427                                      NSWindow** window) {
428   *window = nullptr;
429   RefPtr<BrowsingContext> browsingContext(
430       BrowsingContext::Get(browsingContextId));
431   if (!browsingContext) {
432     return NS_ERROR_NOT_AVAILABLE;
433   }
434   CanonicalBrowsingContext* canonicalBrowsingContext =
435       browsingContext->Canonical();
436   if (!canonicalBrowsingContext) {
437     return NS_ERROR_NOT_AVAILABLE;
438   }
439   nsCOMPtr<nsIWidget> widget(
440       canonicalBrowsingContext->GetParentProcessWidgetContaining());
441   if (!widget) {
442     return NS_ERROR_NOT_AVAILABLE;
443   }
444   *window = static_cast<NSWindow*>(widget->GetNativeData(NS_NATIVE_WINDOW));
445   return NS_OK;
447 #pragma clang diagnostic pop
449 already_AddRefed<nsIWebAuthnService> NewMacOSWebAuthnServiceIfAvailable() {
450   MOZ_ASSERT(XRE_IsParentProcess());
451   if (!StaticPrefs::security_webauthn_enable_macos_passkeys()) {
452     MOZ_LOG(
453         gMacOSWebAuthnServiceLog, LogLevel::Debug,
454         ("macOS platform support for webauthn (passkeys) disabled by pref"));
455     return nullptr;
456   }
457   // This code checks for the entitlement
458   // 'com.apple.developer.web-browser.public-key-credential', which must be
459   // true to be able to use the platform APIs.
460   CFTypeRefPtr<SecTaskRef> entitlementTask(
461       CFTypeRefPtr<SecTaskRef>::WrapUnderCreateRule(
462           SecTaskCreateFromSelf(nullptr)));
463   CFTypeRefPtr<CFBooleanRef> entitlementValue(
464       CFTypeRefPtr<CFBooleanRef>::WrapUnderCreateRule(
465           reinterpret_cast<CFBooleanRef>(SecTaskCopyValueForEntitlement(
466               entitlementTask.get(),
467               CFSTR("com.apple.developer.web-browser.public-key-credential"),
468               nullptr))));
469   if (!entitlementValue || !CFBooleanGetValue(entitlementValue.get())) {
470     MOZ_LOG(
471         gMacOSWebAuthnServiceLog, LogLevel::Warning,
472         ("entitlement com.apple.developer.web-browser.public-key-credential "
473          "not present: platform passkey APIs will not be available"));
474     return nullptr;
475   }
476   nsCOMPtr<nsIWebAuthnService> service(new MacOSWebAuthnService());
477   return service.forget();
480 void MacOSWebAuthnService::AbortTransaction(nsresult aError) {
481   MOZ_ASSERT(NS_IsMainThread());
482   if (mRegisterPromise) {
483     Unused << mRegisterPromise->Reject(aError);
484     mRegisterPromise = nullptr;
485   }
486   if (mSignPromise) {
487     Unused << mSignPromise->Reject(aError);
488     mSignPromise = nullptr;
489   }
490   ReleasePlatformResources();
493 #pragma clang diagnostic push
494 #pragma clang diagnostic ignored "-Wnullability-completeness"
495 NS_IMPL_ISUPPORTS(MacOSWebAuthnService, nsIWebAuthnService)
496 #pragma clang diagnostic pop
498 NS_IMETHODIMP
499 MacOSWebAuthnService::MakeCredential(uint64_t aTransactionId,
500                                      uint64_t aBrowsingContextId,
501                                      nsIWebAuthnRegisterArgs* aArgs,
502                                      nsIWebAuthnRegisterPromise* aPromise) {
503   Reset();
504   auto guard = mTransactionState.Lock();
505   *guard = Some(TransactionState{
506       aTransactionId,
507       aBrowsingContextId,
508       Nothing(),
509       Nothing(),
510       Nothing(),
511   });
512   NS_DispatchToMainThread(NS_NewRunnableFunction(
513       "MacOSWebAuthnService::MakeCredential",
514       [self = RefPtr{this}, browsingContextId(aBrowsingContextId),
515        aArgs = nsCOMPtr{aArgs}, aPromise = nsCOMPtr{aPromise}]() {
516         self->mRegisterPromise = aPromise;
518         nsAutoString rpId;
519         Unused << aArgs->GetRpId(rpId);
520         NSString* rpIdNS = nsCocoaUtils::ToNSString(rpId);
522         nsTArray<uint8_t> challenge;
523         Unused << aArgs->GetChallenge(challenge);
524         NSData* challengeNS = [NSData dataWithBytes:challenge.Elements()
525                                              length:challenge.Length()];
527         nsTArray<uint8_t> userId;
528         Unused << aArgs->GetUserId(userId);
529         NSData* userIdNS = [NSData dataWithBytes:userId.Elements()
530                                           length:userId.Length()];
532         nsAutoString userName;
533         Unused << aArgs->GetUserName(userName);
534         NSString* userNameNS = nsCocoaUtils::ToNSString(userName);
536         nsAutoString userDisplayName;
537         Unused << aArgs->GetUserName(userDisplayName);
538         NSString* userDisplayNameNS = nsCocoaUtils::ToNSString(userDisplayName);
540         nsTArray<int32_t> coseAlgs;
541         Unused << aArgs->GetCoseAlgs(coseAlgs);
542         NSMutableArray* credentialParameters = [[NSMutableArray alloc] init];
543         for (const auto& coseAlg : coseAlgs) {
544           ASAuthorizationPublicKeyCredentialParameters* credentialParameter =
545               [[ASAuthorizationPublicKeyCredentialParameters alloc]
546                   initWithAlgorithm:coseAlg];
547           [credentialParameters addObject:credentialParameter];
548         }
550         nsTArray<nsTArray<uint8_t>> excludeList;
551         Unused << aArgs->GetExcludeList(excludeList);
552         nsTArray<uint8_t> excludeListTransports;
553         Unused << aArgs->GetExcludeListTransports(excludeListTransports);
554         if (excludeList.Length() != excludeListTransports.Length()) {
555           self->mRegisterPromise->Reject(NS_ERROR_INVALID_ARG);
556           return;
557         }
559         Maybe<ASAuthorizationPublicKeyCredentialUserVerificationPreference>
560             userVerificationPreference = Nothing();
561         nsAutoString userVerification;
562         Unused << aArgs->GetUserVerification(userVerification);
563         if (userVerification.EqualsLiteral(
564                 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
565           userVerificationPreference.emplace(
566               ASAuthorizationPublicKeyCredentialUserVerificationPreferenceRequired);
567         } else if (userVerification.EqualsLiteral(
568                        MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
569           userVerificationPreference.emplace(
570               ASAuthorizationPublicKeyCredentialUserVerificationPreferencePreferred);
571         } else if (
572             userVerification.EqualsLiteral(
573                 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED)) {
574           userVerificationPreference.emplace(
575               ASAuthorizationPublicKeyCredentialUserVerificationPreferenceDiscouraged);
576         }
578         // The API doesn't support attestation for platform passkeys and shows
579         // no consent UI for non-none attestation for cross-platform devices,
580         // so this must always be none.
581         ASAuthorizationPublicKeyCredentialAttestationKind
582             attestationPreference =
583                 ASAuthorizationPublicKeyCredentialAttestationKindNone;
585         // Initialize the platform provider with the rpId.
586         ASAuthorizationPlatformPublicKeyCredentialProvider* platformProvider =
587             [[ASAuthorizationPlatformPublicKeyCredentialProvider alloc]
588                 initWithRelyingPartyIdentifier:rpIdNS];
589         // Make a credential registration request with the challenge, userName,
590         // and userId.
591         ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest*
592             platformRegistrationRequest = [platformProvider
593                 createCredentialRegistrationRequestWithChallenge:challengeNS
594                                                             name:userNameNS
595                                                           userID:userIdNS];
596         [platformProvider release];
597         platformRegistrationRequest.attestationPreference =
598             attestationPreference;
599         if (userVerificationPreference.isSome()) {
600           platformRegistrationRequest.userVerificationPreference =
601               *userVerificationPreference;
602         }
604         // Initialize the cross-platform provider with the rpId.
605         ASAuthorizationSecurityKeyPublicKeyCredentialProvider*
606             crossPlatformProvider =
607                 [[ASAuthorizationSecurityKeyPublicKeyCredentialProvider alloc]
608                     initWithRelyingPartyIdentifier:rpIdNS];
609         // Make a credential registration request with the challenge,
610         // userDisplayName, userName, and userId.
611         ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest*
612             crossPlatformRegistrationRequest = [crossPlatformProvider
613                 createCredentialRegistrationRequestWithChallenge:challengeNS
614                                                      displayName:
615                                                          userDisplayNameNS
616                                                             name:userNameNS
617                                                           userID:userIdNS];
618         [crossPlatformProvider release];
619         crossPlatformRegistrationRequest.attestationPreference =
620             attestationPreference;
621         crossPlatformRegistrationRequest.credentialParameters =
622             credentialParameters;
623         if (userVerificationPreference.isSome()) {
624           crossPlatformRegistrationRequest.userVerificationPreference =
625               *userVerificationPreference;
626         }
627         nsTArray<uint8_t> clientDataHash;
628         nsresult rv = aArgs->GetClientDataHash(clientDataHash);
629         if (NS_FAILED(rv)) {
630           self->mRegisterPromise->Reject(rv);
631           return;
632         }
633         nsAutoString authenticatorAttachment;
634         rv = aArgs->GetAuthenticatorAttachment(authenticatorAttachment);
635         if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) {
636           self->mRegisterPromise->Reject(rv);
637           return;
638         }
639         NSMutableArray* requests = [[NSMutableArray alloc] init];
640         if (authenticatorAttachment.EqualsLiteral(
641                 MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
642           [requests addObject:platformRegistrationRequest];
643         } else if (authenticatorAttachment.EqualsLiteral(
644                        MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
645           [requests addObject:crossPlatformRegistrationRequest];
646         } else {
647           // Regarding the value of authenticator attachment, according to the
648           // specification, "client platforms MUST ignore unknown values,
649           // treating an unknown value as if the member does not exist".
650           [requests addObject:platformRegistrationRequest];
651           [requests addObject:crossPlatformRegistrationRequest];
652         }
653         self->PerformRequests(
654             requests, std::move(clientDataHash), std::move(excludeList),
655             std::move(excludeListTransports), browsingContextId);
656       }));
657   return NS_OK;
660 void MacOSWebAuthnService::PerformRequests(
661     NSArray<ASAuthorizationRequest*>* aRequests,
662     nsTArray<uint8_t>&& aClientDataHash,
663     nsTArray<nsTArray<uint8_t>>&& aCredentialList,
664     nsTArray<uint8_t>&& aCredentialListTransports,
665     uint64_t aBrowsingContextId) {
666   MOZ_ASSERT(NS_IsMainThread());
667   // Create a MacOSAuthorizationController and initialize it with the requests.
668   MOZ_ASSERT(!mAuthorizationController);
669   mAuthorizationController = [[MacOSAuthorizationController alloc]
670       initWithAuthorizationRequests:aRequests];
671   [mAuthorizationController
672               stashClientDataHash:std::move(aClientDataHash)
673                 andCredentialList:std::move(aCredentialList)
674       andCredentialListTransports:std::move(aCredentialListTransports)];
676   // Set up the delegate to run when the operation completes.
677   MOZ_ASSERT(!mRequestDelegate);
678   mRequestDelegate = [[MacOSAuthenticatorRequestDelegate alloc] init];
679   [mRequestDelegate setCallback:this];
680   mAuthorizationController.delegate = mRequestDelegate;
682   // Create a presentation context provider so the API knows which window
683   // made the request.
684   NSWindow* window = nullptr;
685   nsresult rv = BrowsingContextIdToNSWindow(aBrowsingContextId, &window);
686   if (NS_FAILED(rv)) {
687     AbortTransaction(NS_ERROR_DOM_INVALID_STATE_ERR);
688     return;
689   }
690   MOZ_ASSERT(!mPresentationContextProvider);
691   mPresentationContextProvider =
692       [[MacOSAuthenticatorPresentationContextProvider alloc] init];
693   mPresentationContextProvider.window = window;
694   mAuthorizationController.presentationContextProvider =
695       mPresentationContextProvider;
697   // Finally, perform the request.
698   [mAuthorizationController performRequests];
701 void MacOSWebAuthnService::FinishMakeCredential(
702     const nsTArray<uint8_t>& aRawAttestationObject,
703     const nsTArray<uint8_t>& aCredentialId,
704     const nsTArray<nsString>& aTransports,
705     const Maybe<nsString>& aAuthenticatorAttachment) {
706   MOZ_ASSERT(NS_IsMainThread());
707   if (!mRegisterPromise) {
708     return;
709   }
711   RefPtr<WebAuthnRegisterResult> result(new WebAuthnRegisterResult(
712       aRawAttestationObject, Nothing(), aCredentialId, aTransports,
713       aAuthenticatorAttachment));
714   Unused << mRegisterPromise->Resolve(result);
715   mRegisterPromise = nullptr;
718 NS_IMETHODIMP
719 MacOSWebAuthnService::GetAssertion(uint64_t aTransactionId,
720                                    uint64_t aBrowsingContextId,
721                                    nsIWebAuthnSignArgs* aArgs,
722                                    nsIWebAuthnSignPromise* aPromise) {
723   Reset();
725   auto guard = mTransactionState.Lock();
726   *guard = Some(TransactionState{
727       aTransactionId,
728       aBrowsingContextId,
729       Some(RefPtr{aArgs}),
730       Some(RefPtr{aPromise}),
731       Nothing(),
732   });
734   bool conditionallyMediated;
735   Unused << aArgs->GetConditionallyMediated(&conditionallyMediated);
736   if (!conditionallyMediated) {
737     DoGetAssertion(Nothing(), guard);
738     return NS_OK;
739   }
741   // Using conditional mediation, so dispatch a task to collect any available
742   // passkeys.
743   NS_DispatchToMainThread(NS_NewRunnableFunction(
744       "platformCredentialsForRelyingParty",
745       [self = RefPtr{this}, aTransactionId, aArgs = nsCOMPtr{aArgs}]() {
746         // This handler is called when platformCredentialsForRelyingParty
747         // completes.
748         auto credentialsCompletionHandler = ^(
749             NSArray<ASAuthorizationWebBrowserPlatformPublicKeyCredential*>*
750                 credentials) {
751           nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>> autoFillEntries;
752           for (NSUInteger i = 0; i < credentials.count; i++) {
753             const auto& credential = credentials[i];
754             nsAutoString userName;
755             nsCocoaUtils::GetStringForNSString(credential.name, userName);
756             nsAutoString rpId;
757             nsCocoaUtils::GetStringForNSString(credential.relyingParty, rpId);
758             autoFillEntries.AppendElement(new WebAuthnAutoFillEntry(
759                 nsIWebAuthnAutoFillEntry::PROVIDER_PLATFORM_MACOS, userName,
760                 rpId, NSDataToArray(credential.credentialID)));
761           }
762           auto guard = self->mTransactionState.Lock();
763           if (guard->isSome() && guard->ref().transactionId == aTransactionId) {
764             guard->ref().autoFillEntries.emplace(std::move(autoFillEntries));
765           }
766         };
767         // This handler is called when
768         // requestAuthorizationForPublicKeyCredentials completes.
769         auto authorizationHandler = ^(
770             ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState
771                 authorizationState) {
772           // If authorized, list any available passkeys.
773           if (authorizationState ==
774               ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationStateAuthorized) {
775             nsAutoString rpId;
776             Unused << aArgs->GetRpId(rpId);
777             [self->mCredentialManager
778                 platformCredentialsForRelyingParty:nsCocoaUtils::ToNSString(
779                                                        rpId)
780                                  completionHandler:
781                                      credentialsCompletionHandler];
782           }
783         };
784         if (!self->mCredentialManager) {
785           self->mCredentialManager =
786               [[ASAuthorizationWebBrowserPublicKeyCredentialManager alloc]
787                   init];
788         }
789         // Request authorization to examine any available passkeys. This will
790         // cause a permission prompt to appear once.
791         [self->mCredentialManager
792             requestAuthorizationForPublicKeyCredentials:authorizationHandler];
793       }));
795   return NS_OK;
798 void MacOSWebAuthnService::DoGetAssertion(
799     Maybe<nsTArray<uint8_t>>&& aSelectedCredentialId,
800     const TransactionStateMutex::AutoLock& aGuard) {
801   if (aGuard->isNothing() || aGuard->ref().pendingSignArgs.isNothing() ||
802       aGuard->ref().pendingSignPromise.isNothing()) {
803     return;
804   }
806   // Take the pending Args and Promise to prevent repeated calls to
807   // DoGetAssertion for this transaction.
808   RefPtr<nsIWebAuthnSignArgs> aArgs = aGuard->ref().pendingSignArgs.extract();
809   RefPtr<nsIWebAuthnSignPromise> aPromise =
810       aGuard->ref().pendingSignPromise.extract();
811   uint64_t aBrowsingContextId = aGuard->ref().browsingContextId;
813   NS_DispatchToMainThread(NS_NewRunnableFunction(
814       "MacOSWebAuthnService::MakeCredential",
815       [self = RefPtr{this}, browsingContextId(aBrowsingContextId), aArgs,
816        aPromise,
817        aSelectedCredentialId = std::move(aSelectedCredentialId)]() mutable {
818         self->mSignPromise = aPromise;
820         nsAutoString rpId;
821         Unused << aArgs->GetRpId(rpId);
822         NSString* rpIdNS = nsCocoaUtils::ToNSString(rpId);
824         nsTArray<uint8_t> challenge;
825         Unused << aArgs->GetChallenge(challenge);
826         NSData* challengeNS = [NSData dataWithBytes:challenge.Elements()
827                                              length:challenge.Length()];
829         nsTArray<nsTArray<uint8_t>> allowList;
830         nsTArray<uint8_t> allowListTransports;
831         if (aSelectedCredentialId.isSome()) {
832           allowList.AppendElement(aSelectedCredentialId.extract());
833           allowListTransports.AppendElement(
834               MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL);
835         } else {
836           Unused << aArgs->GetAllowList(allowList);
837           Unused << aArgs->GetAllowListTransports(allowListTransports);
838         }
839         NSMutableArray* platformAllowedCredentials =
840             [[NSMutableArray alloc] init];
841         for (const auto& allowedCredentialId : allowList) {
842           NSData* allowedCredentialIdNS =
843               [NSData dataWithBytes:allowedCredentialId.Elements()
844                              length:allowedCredentialId.Length()];
845           ASAuthorizationPlatformPublicKeyCredentialDescriptor*
846               allowedCredential =
847                   [[ASAuthorizationPlatformPublicKeyCredentialDescriptor alloc]
848                       initWithCredentialID:allowedCredentialIdNS];
849           [platformAllowedCredentials addObject:allowedCredential];
850         }
851         const Class securityKeyPublicKeyCredentialDescriptorClass =
852             NSClassFromString(
853                 @"ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor");
854         NSArray<ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor*>*
855             crossPlatformAllowedCredentials =
856                 CredentialListsToCredentialDescriptorArray(
857                     allowList, allowListTransports,
858                     securityKeyPublicKeyCredentialDescriptorClass);
860         Maybe<ASAuthorizationPublicKeyCredentialUserVerificationPreference>
861             userVerificationPreference = Nothing();
862         nsAutoString userVerification;
863         Unused << aArgs->GetUserVerification(userVerification);
864         if (userVerification.EqualsLiteral(
865                 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
866           userVerificationPreference.emplace(
867               ASAuthorizationPublicKeyCredentialUserVerificationPreferenceRequired);
868         } else if (userVerification.EqualsLiteral(
869                        MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
870           userVerificationPreference.emplace(
871               ASAuthorizationPublicKeyCredentialUserVerificationPreferencePreferred);
872         } else if (
873             userVerification.EqualsLiteral(
874                 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED)) {
875           userVerificationPreference.emplace(
876               ASAuthorizationPublicKeyCredentialUserVerificationPreferenceDiscouraged);
877         }
879         // Initialize the platform provider with the rpId.
880         ASAuthorizationPlatformPublicKeyCredentialProvider* platformProvider =
881             [[ASAuthorizationPlatformPublicKeyCredentialProvider alloc]
882                 initWithRelyingPartyIdentifier:rpIdNS];
883         // Make a credential assertion request with the challenge.
884         ASAuthorizationPlatformPublicKeyCredentialAssertionRequest*
885             platformAssertionRequest = [platformProvider
886                 createCredentialAssertionRequestWithChallenge:challengeNS];
887         [platformProvider release];
888         platformAssertionRequest.allowedCredentials =
889             platformAllowedCredentials;
890         if (userVerificationPreference.isSome()) {
891           platformAssertionRequest.userVerificationPreference =
892               *userVerificationPreference;
893         }
895         // Initialize the cross-platform provider with the rpId.
896         ASAuthorizationSecurityKeyPublicKeyCredentialProvider*
897             crossPlatformProvider =
898                 [[ASAuthorizationSecurityKeyPublicKeyCredentialProvider alloc]
899                     initWithRelyingPartyIdentifier:rpIdNS];
900         // Make a credential assertion request with the challenge.
901         ASAuthorizationSecurityKeyPublicKeyCredentialAssertionRequest*
902             crossPlatformAssertionRequest = [crossPlatformProvider
903                 createCredentialAssertionRequestWithChallenge:challengeNS];
904         [crossPlatformProvider release];
905         crossPlatformAssertionRequest.allowedCredentials =
906             crossPlatformAllowedCredentials;
907         if (userVerificationPreference.isSome()) {
908           crossPlatformAssertionRequest.userVerificationPreference =
909               *userVerificationPreference;
910         }
911         nsTArray<uint8_t> clientDataHash;
912         nsresult rv = aArgs->GetClientDataHash(clientDataHash);
913         if (NS_FAILED(rv)) {
914           self->mSignPromise->Reject(rv);
915           return;
916         }
917         nsTArray<nsTArray<uint8_t>> unusedCredentialIds;
918         nsTArray<uint8_t> unusedTransports;
919         // allowList and allowListTransports won't actually get used.
920         self->PerformRequests(
921             @[ platformAssertionRequest, crossPlatformAssertionRequest ],
922             std::move(clientDataHash), std::move(allowList),
923             std::move(allowListTransports), browsingContextId);
924       }));
927 void MacOSWebAuthnService::FinishGetAssertion(
928     const nsTArray<uint8_t>& aCredentialId, const nsTArray<uint8_t>& aSignature,
929     const nsTArray<uint8_t>& aAuthenticatorData,
930     const nsTArray<uint8_t>& aUserHandle,
931     const Maybe<nsString>& aAuthenticatorAttachment) {
932   MOZ_ASSERT(NS_IsMainThread());
933   if (!mSignPromise) {
934     return;
935   }
937   RefPtr<WebAuthnSignResult> result(new WebAuthnSignResult(
938       aAuthenticatorData, Nothing(), aCredentialId, aSignature, aUserHandle,
939       aAuthenticatorAttachment));
940   Unused << mSignPromise->Resolve(result);
941   mSignPromise = nullptr;
944 void MacOSWebAuthnService::ReleasePlatformResources() {
945   MOZ_ASSERT(NS_IsMainThread());
946   [mCredentialManager release];
947   mCredentialManager = nil;
948   [mAuthorizationController release];
949   mAuthorizationController = nil;
950   [mRequestDelegate release];
951   mRequestDelegate = nil;
952   [mPresentationContextProvider release];
953   mPresentationContextProvider = nil;
956 NS_IMETHODIMP
957 MacOSWebAuthnService::Reset() {
958   auto guard = mTransactionState.Lock();
959   if (guard->isSome()) {
960     if (guard->ref().pendingSignPromise.isSome()) {
961       // This request was never dispatched to the platform API, so
962       // we need to reject the promise ourselves.
963       guard->ref().pendingSignPromise.ref()->Reject(
964           NS_ERROR_DOM_NOT_ALLOWED_ERR);
965     }
966     guard->reset();
967   }
968   NS_DispatchToMainThread(NS_NewRunnableFunction(
969       "MacOSWebAuthnService::Cancel", [self = RefPtr{this}] {
970         // cancel results in the delegate's didCompleteWithError method being
971         // called, which will release all platform resources.
972         [self->mAuthorizationController cancel];
973       }));
974   return NS_OK;
977 NS_IMETHODIMP
978 MacOSWebAuthnService::GetIsUVPAA(bool* aAvailable) {
979   *aAvailable = true;
980   return NS_OK;
983 NS_IMETHODIMP
984 MacOSWebAuthnService::Cancel(uint64_t aTransactionId) {
985   return NS_ERROR_NOT_IMPLEMENTED;
988 NS_IMETHODIMP
989 MacOSWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId,
990                                                const nsAString& aOrigin,
991                                                uint64_t* aRv) {
992   auto guard = mTransactionState.Lock();
993   if (guard->isNothing() ||
994       guard->ref().browsingContextId != aBrowsingContextId ||
995       guard->ref().pendingSignArgs.isNothing()) {
996     *aRv = 0;
997     return NS_OK;
998   }
1000   nsString origin;
1001   Unused << guard->ref().pendingSignArgs.ref()->GetOrigin(origin);
1002   if (origin != aOrigin) {
1003     *aRv = 0;
1004     return NS_OK;
1005   }
1007   *aRv = guard->ref().transactionId;
1008   return NS_OK;
1011 NS_IMETHODIMP
1012 MacOSWebAuthnService::GetAutoFillEntries(
1013     uint64_t aTransactionId, nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>& aRv) {
1014   auto guard = mTransactionState.Lock();
1015   if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1016       guard->ref().pendingSignArgs.isNothing() ||
1017       guard->ref().autoFillEntries.isNothing()) {
1018     return NS_ERROR_NOT_AVAILABLE;
1019   }
1020   aRv.Assign(guard->ref().autoFillEntries.ref());
1021   return NS_OK;
1024 NS_IMETHODIMP
1025 MacOSWebAuthnService::SelectAutoFillEntry(
1026     uint64_t aTransactionId, const nsTArray<uint8_t>& aCredentialId) {
1027   auto guard = mTransactionState.Lock();
1028   if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1029       guard->ref().pendingSignArgs.isNothing()) {
1030     return NS_ERROR_NOT_AVAILABLE;
1031   }
1033   nsTArray<nsTArray<uint8_t>> allowList;
1034   Unused << guard->ref().pendingSignArgs.ref()->GetAllowList(allowList);
1035   if (!allowList.IsEmpty() && !allowList.Contains(aCredentialId)) {
1036     return NS_ERROR_FAILURE;
1037   }
1039   Maybe<nsTArray<uint8_t>> id;
1040   id.emplace();
1041   id.ref().Assign(aCredentialId);
1042   DoGetAssertion(std::move(id), guard);
1044   return NS_OK;
1047 NS_IMETHODIMP
1048 MacOSWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) {
1049   auto guard = mTransactionState.Lock();
1050   if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1051       guard->ref().pendingSignArgs.isNothing()) {
1052     return NS_ERROR_NOT_AVAILABLE;
1053   }
1054   DoGetAssertion(Nothing(), guard);
1055   return NS_OK;
1058 NS_IMETHODIMP
1059 MacOSWebAuthnService::PinCallback(uint64_t aTransactionId,
1060                                   const nsACString& aPin) {
1061   return NS_ERROR_NOT_IMPLEMENTED;
1064 NS_IMETHODIMP
1065 MacOSWebAuthnService::ResumeMakeCredential(uint64_t aTransactionId,
1066                                            bool aForceNoneAttestation) {
1067   return NS_ERROR_NOT_IMPLEMENTED;
1070 NS_IMETHODIMP
1071 MacOSWebAuthnService::SelectionCallback(uint64_t aTransactionId,
1072                                         uint64_t aIndex) {
1073   return NS_ERROR_NOT_IMPLEMENTED;
1076 NS_IMETHODIMP
1077 MacOSWebAuthnService::AddVirtualAuthenticator(
1078     const nsACString& protocol, const nsACString& transport,
1079     bool hasResidentKey, bool hasUserVerification, bool isUserConsenting,
1080     bool isUserVerified, uint64_t* _retval) {
1081   return NS_ERROR_NOT_IMPLEMENTED;
1084 NS_IMETHODIMP
1085 MacOSWebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
1086   return NS_ERROR_NOT_IMPLEMENTED;
1089 NS_IMETHODIMP
1090 MacOSWebAuthnService::AddCredential(uint64_t authenticatorId,
1091                                     const nsACString& credentialId,
1092                                     bool isResidentCredential,
1093                                     const nsACString& rpId,
1094                                     const nsACString& privateKey,
1095                                     const nsACString& userHandle,
1096                                     uint32_t signCount) {
1097   return NS_ERROR_NOT_IMPLEMENTED;
1100 NS_IMETHODIMP
1101 MacOSWebAuthnService::GetCredentials(
1102     uint64_t authenticatorId,
1103     nsTArray<RefPtr<nsICredentialParameters>>& _retval) {
1104   return NS_ERROR_NOT_IMPLEMENTED;
1107 NS_IMETHODIMP
1108 MacOSWebAuthnService::RemoveCredential(uint64_t authenticatorId,
1109                                        const nsACString& credentialId) {
1110   return NS_ERROR_NOT_IMPLEMENTED;
1113 NS_IMETHODIMP
1114 MacOSWebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
1115   return NS_ERROR_NOT_IMPLEMENTED;
1118 NS_IMETHODIMP
1119 MacOSWebAuthnService::SetUserVerified(uint64_t authenticatorId,
1120                                       bool isUserVerified) {
1121   return NS_ERROR_NOT_IMPLEMENTED;
1124 NS_IMETHODIMP
1125 MacOSWebAuthnService::Listen() { return NS_ERROR_NOT_IMPLEMENTED; }
1127 NS_IMETHODIMP
1128 MacOSWebAuthnService::RunCommand(const nsACString& cmd) {
1129   return NS_ERROR_NOT_IMPLEMENTED;
1132 }  // namespace mozilla::dom
1134 NS_ASSUME_NONNULL_END