From 320a766374bc4d265798e6ac60d1ddec395ad519 Mon Sep 17 00:00:00 2001 From: Cristian Tuns Date: Fri, 1 Dec 2023 17:59:13 -0500 Subject: [PATCH] Backed out 4 changesets (bug 1838932, bug 1864544, bug 1853951, bug 1824215) for causing build bustages in WinWebAuthnService.cpp CLOSED TREE Backed out changeset 8199d5ce1bfa (bug 1864544) Backed out changeset 1084e05b2914 (bug 1853951) Backed out changeset 55320a72238f (bug 1824215) Backed out changeset 876476ccd759 (bug 1838932) --- .../formautofill/test/browser/head.js | 1 - .../locales/en-US/browser/webauthnDialog.ftl | 7 - dom/base/AutocompleteFieldList.h | 13 - dom/base/nsContentUtils.cpp | 88 +------ .../CredentialsContainer.cpp | 9 +- dom/html/test/forms/test_autocomplete.html | 27 -- .../test/forms/test_autocompleteinfo.html | 29 --- dom/webauthn/AndroidWebAuthnService.cpp | 42 +-- dom/webauthn/MacOSWebAuthnService.mm | 28 -- dom/webauthn/PWebAuthnTransaction.ipdl | 1 - dom/webauthn/PublicKeyCredential.cpp | 6 +- dom/webauthn/WebAuthnArgs.cpp | 6 - dom/webauthn/WebAuthnAutoFillEntry.cpp | 35 --- dom/webauthn/WebAuthnAutoFillEntry.h | 51 ---- dom/webauthn/WebAuthnManager.cpp | 3 +- dom/webauthn/WebAuthnManager.h | 1 - dom/webauthn/WebAuthnService.cpp | 72 +----- dom/webauthn/WinWebAuthnService.cpp | 239 +++--------------- dom/webauthn/WinWebAuthnService.h | 17 +- dom/webauthn/authrs_bridge/src/lib.rs | 194 +++----------- dom/webauthn/authrs_bridge/src/test_token.rs | 75 +----- dom/webauthn/moz.build | 1 - dom/webauthn/nsIWebAuthnArgs.idl | 2 - dom/webauthn/nsIWebAuthnService.idl | 35 --- dom/webauthn/tests/browser/browser.toml | 3 - .../browser_webauthn_conditional_mediation.js | 124 --------- dom/webauthn/tests/browser/head.js | 30 +-- dom/webauthn/tests/mochitest.toml | 1 - dom/webidl/AutocompleteInfo.webidl | 1 - modules/libpref/init/StaticPrefList.yaml | 10 - testing/profiles/web-platform/user.js | 2 - .../form-autocomplete.html.ini | 6 + .../conditional-mediation.https.html.ini | 8 +- .../formautofill/shared/FieldScanner.sys.mjs | 2 - .../passwordmgr/LoginAutoComplete.sys.mjs | 10 - .../passwordmgr/LoginManagerParent.sys.mjs | 40 +-- .../integrations/WebAuthnFeature.sys.mjs | 129 ---------- toolkit/components/satchel/moz.build | 1 - 38 files changed, 122 insertions(+), 1227 deletions(-) delete mode 100644 dom/webauthn/WebAuthnAutoFillEntry.cpp delete mode 100644 dom/webauthn/WebAuthnAutoFillEntry.h delete mode 100644 dom/webauthn/tests/browser/browser_webauthn_conditional_mediation.js delete mode 100644 toolkit/components/satchel/integrations/WebAuthnFeature.sys.mjs diff --git a/browser/extensions/formautofill/test/browser/head.js b/browser/extensions/formautofill/test/browser/head.js index fded49962426..c57260798ed0 100644 --- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -933,7 +933,6 @@ function verifySectionFieldDetails(sections, expectedSectionsInfo) { section: "", contactType: "", addressType: "", - credentialType: "", }, ...expectedSection.default, ...expectedFieldDetail, diff --git a/browser/locales/en-US/browser/webauthnDialog.ftl b/browser/locales/en-US/browser/webauthnDialog.ftl index 14f6ac7184d8..1034739269c2 100644 --- a/browser/locales/en-US/browser/webauthnDialog.ftl +++ b/browser/locales/en-US/browser/webauthnDialog.ftl @@ -14,13 +14,6 @@ webauthn-pin-required-prompt = Please enter the PIN for your device. webauthn-select-sign-result-unknown-account = Unknown account -webauthn-a-passkey-label = Use a passkey -webauthn-another-passkey-label = Use another passkey - -# Variables: -# $domain (String): the domain of the site. -webauthn-specific-passkey-label = Passkey for { $domain } - # Variables: # $retriesLeft (Number): number of tries left webauthn-uv-invalid-long-prompt = diff --git a/dom/base/AutocompleteFieldList.h b/dom/base/AutocompleteFieldList.h index 5796596f7fe9..7856a77772ce 100644 --- a/dom/base/AutocompleteFieldList.h +++ b/dom/base/AutocompleteFieldList.h @@ -38,11 +38,6 @@ #define DEFINED_AUTOCOMPLETE_FIELD_CONTACT_HINT #endif -#ifndef AUTOCOMPLETE_CREDENTIAL_TYPE -#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) -#define DEFINED_AUTOCOMPLETE_CREDENTIAL_TYPE -#endif - #ifndef AUTOCOMPLETE_CATEGORY #define AUTOCOMPLETE_CATEGORY(name_, value_) #define DEFINED_AUTOCOMPLETE_CATEGORY @@ -185,9 +180,6 @@ AUTOCOMPLETE_FIELD_CONTACT_HINT(MOBILE, "mobile") AUTOCOMPLETE_FIELD_CONTACT_HINT(FAX, "fax") AUTOCOMPLETE_FIELD_CONTACT_HINT(PAGER, "pager") -// Credential types -AUTOCOMPLETE_CREDENTIAL_TYPE(WEBAUTHN, "webauthn") - AUTOCOMPLETE_CATEGORY(NORMAL, "normal") AUTOCOMPLETE_CATEGORY(CONTACT, "contact") //----------------------------------------------------- @@ -227,11 +219,6 @@ AUTOCOMPLETE_CATEGORY(CONTACT, "contact") #undef DEFINED_AUTOCOMPLETE_FIELD_CONTACT_HINT #endif -#ifdef DEFINED_AUTOCOMPLETE_CREDENTIAL_TYPE -#undef AUTOCOMPLETE_CREDENTIAL_TYPE -#undef DEFINED_AUTOCOMPLETE_CREDENTIAL_TYPE -#endif - #ifdef DEFINED_AUTOCOMPLETE_CATEGORY #undef AUTOCOMPLETE_CATEGORY #undef DEFINED_AUTOCOMPLETE_CATEGORY diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 427e387ff3aa..94f9f290ed1f 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -549,13 +549,6 @@ enum AutocompleteFieldContactHint : uint8_t { #undef AUTOCOMPLETE_FIELD_CONTACT_HINT }; -enum AutocompleteCredentialType : uint8_t { -#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ - eAutocompleteCredentialType_##name_, -#include "AutocompleteFieldList.h" -#undef AUTOCOMPLETE_CREDENTIAL_TYPE -}; - enum AutocompleteCategory { #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_, #include "AutocompleteFieldList.h" @@ -612,13 +605,6 @@ static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = { #undef AUTOCOMPLETE_FIELD_CONTACT_HINT {nullptr, 0}}; -static const nsAttrValue::EnumTable kAutocompleteCredentialTypeTable[] = { -#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ - {value_, eAutocompleteCredentialType_##name_}, -#include "AutocompleteFieldList.h" -#undef AUTOCOMPLETE_CREDENTIAL_TYPE - {nullptr, 0}}; - namespace { static PLDHashTable* sEventListenerManagersHash; @@ -1179,18 +1165,6 @@ nsContentUtils::SerializeAutocompleteAttribute( } aResult += info.mFieldName; } - - // The autocomplete attribute value "webauthn" is interpreted as both a - // field name and a credential type. The corresponding IDL-exposed autofill - // value is "webauthn", not "webauthn webauthn". - if (!info.mCredentialType.IsEmpty() && - !(info.mCredentialType.Equals(u"webauthn"_ns) && - info.mCredentialType.Equals(aResult))) { - if (!aResult.IsEmpty()) { - aResult += ' '; - } - aResult += info.mCredentialType; - } } return state; @@ -1224,7 +1198,7 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( } uint32_t numTokens = aAttrVal->GetAtomCount(); - if (!numTokens || numTokens > INT32_MAX) { + if (!numTokens) { return eAutocompleteAttrState_Invalid; } @@ -1232,46 +1206,6 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); AutocompleteCategory category; nsAttrValue enumValue; - nsAutoString credentialTypeStr; - - bool result = enumValue.ParseEnumValue( - tokenString, kAutocompleteCredentialTypeTable, false); - if (result) { - if (!enumValue.Equals(u"webauthn"_ns, eIgnoreCase) || numTokens > 5) { - return eAutocompleteAttrState_Invalid; - } - enumValue.ToString(credentialTypeStr); - ASCIIToLower(credentialTypeStr); - // category is Credential and the indexth token is "webauthn" - if (index == 0) { - aInfo.mFieldName.Assign(credentialTypeStr); - aInfo.mCredentialType.Assign(credentialTypeStr); - return eAutocompleteAttrState_Valid; - } - - --index; - tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); - - // Only the Normal and Contact categories are allowed with webauthn - // - disallow Credential - if (enumValue.ParseEnumValue(tokenString, kAutocompleteCredentialTypeTable, - false)) { - return eAutocompleteAttrState_Invalid; - } - // - disallow Off and Automatic - if (enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, - false)) { - if (enumValue.Equals(u"off"_ns, eIgnoreCase) || - enumValue.Equals(u"on"_ns, eIgnoreCase)) { - return eAutocompleteAttrState_Invalid; - } - } - - // Proceed to process the remaining tokens as if "webauthn" was not present. - // We need to decrement numTokens to enforce the correct per-category limits - // on the maximum number of tokens. - --numTokens; - } bool unsupported = false; if (!aGrantAllValidValue) { @@ -1282,10 +1216,9 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( } } - nsAutoString fieldNameStr; - result = + nsAutoString str; + bool result = enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false); - if (result) { // Off/Automatic/Normal categories. if (enumValue.Equals(u"off"_ns, eIgnoreCase) || @@ -1293,10 +1226,9 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( if (numTokens > 1) { return eAutocompleteAttrState_Invalid; } - enumValue.ToString(fieldNameStr); - ASCIIToLower(fieldNameStr); - aInfo.mFieldName.Assign(fieldNameStr); - aInfo.mCredentialType.Assign(credentialTypeStr); + enumValue.ToString(str); + ASCIIToLower(str); + aInfo.mFieldName.Assign(str); aInfo.mCanAutomaticallyPersist = !enumValue.Equals(u"off"_ns, eIgnoreCase); return eAutocompleteAttrState_Valid; @@ -1331,11 +1263,10 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( category = eAutocompleteCategory_CONTACT; } - enumValue.ToString(fieldNameStr); - ASCIIToLower(fieldNameStr); + enumValue.ToString(str); + ASCIIToLower(str); + aInfo.mFieldName.Assign(str); - aInfo.mFieldName.Assign(fieldNameStr); - aInfo.mCredentialType.Assign(credentialTypeStr); aInfo.mCanAutomaticallyPersist = !enumValue.ParseEnumValue( tokenString, kAutocompleteNoPersistFieldNameTable, false); @@ -1402,7 +1333,6 @@ nsContentUtils::InternalSerializeAutocompleteAttribute( aInfo.mAddressType.Truncate(); aInfo.mContactType.Truncate(); aInfo.mFieldName.Truncate(); - aInfo.mCredentialType.Truncate(); return eAutocompleteAttrState_Invalid; } diff --git a/dom/credentialmanagement/CredentialsContainer.cpp b/dom/credentialmanagement/CredentialsContainer.cpp index c17fb5f5eabd..9fb879770deb 100644 --- a/dom/credentialmanagement/CredentialsContainer.cpp +++ b/dom/credentialmanagement/CredentialsContainer.cpp @@ -163,8 +163,9 @@ already_AddRefed CredentialsContainer::Get( return CreateAndRejectWithNotAllowed(mParent, aRv); } - if (conditionallyMediated && - !StaticPrefs::security_webauthn_enable_conditional_mediation()) { + if (conditionallyMediated) { + // Conditional mediation for WebAuthn Get() will be implemented in + // Bug 1838932. RefPtr promise = CreatePromise(mParent, aRv); if (!promise) { return nullptr; @@ -175,8 +176,8 @@ already_AddRefed CredentialsContainer::Get( } EnsureWebAuthnManager(); - return mManager->GetAssertion(aOptions.mPublicKey.Value(), - conditionallyMediated, aOptions.mSignal, aRv); + return mManager->GetAssertion(aOptions.mPublicKey.Value(), aOptions.mSignal, + aRv); } if (aOptions.mIdentity.WasPassed() && diff --git a/dom/html/test/forms/test_autocomplete.html b/dom/html/test/forms/test_autocomplete.html index c98be94eeadb..de92254386d1 100644 --- a/dom/html/test/forms/test_autocomplete.html +++ b/dom/html/test/forms/test_autocomplete.html @@ -33,14 +33,6 @@ var values = [ ["tel-extension", ""], ["foobar", ""], ["section-blue", ""], - [" WEBAUTHN ", "webauthn"], - - // One token + WebAuthn credential type - ["on webauthn", ""], - ["off webauthn", ""], - ["webauthn webauthn", ""], - ["username WebAuthn", "username webauthn"], - ["current-PASSWORD webauthn", "current-password webauthn"], // Two tokens ["on off", ""], @@ -64,11 +56,6 @@ var values = [ ["fax url", ""], ["section-blue name", "section-blue name"], ["section-blue tel", "section-blue tel"], - ["webauthn username", ""], - - // Two tokens + WebAuthn credential type - ["fax url webauthn", ""], - ["shipping tel webauthn", "shipping tel webauthn"], // Three tokens ["billing invalid tel", ""], @@ -84,11 +71,6 @@ var values = [ ["section-blue home address-level2", ""], ["section-blue shipping name", "section-blue shipping name"], ["section-blue mobile tel", "section-blue mobile tel"], - ["shipping webauthn tel", ""], - - // Three tokens + WebAuthn credential type - ["invalid mobile tel webauthn", ""], - ["section-blue shipping name webauthn", "section-blue shipping name webauthn"], // Four tokens ["billing billing mobile tel", ""], @@ -96,19 +78,10 @@ var values = [ ["secti shipping work address-line1", ""], ["section-blue shipping home name", ""], ["section-blue shipping mobile tel", "section-blue shipping mobile tel"], - ["section-blue webauthn mobile tel", ""], - - // Four tokens + WebAuthn credential type - ["section-blue shipping home name webauthn", ""], - ["section-blue shipping mobile tel webauthn", "section-blue shipping mobile tel webauthn"], // Five tokens (invalid) ["billing billing billing mobile tel", ""], ["section-blue section-blue billing mobile tel", ""], - ["section-blue section-blue billing webauthn tel", ""], - - // Five tokens + WebAuthn credential type (invalid) - ["billing billing billing mobile tel webauthn", ""], ]; var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints. diff --git a/dom/html/test/forms/test_autocompleteinfo.html b/dom/html/test/forms/test_autocompleteinfo.html index a3357ac8de15..5f8673d9ba6c 100644 --- a/dom/html/test/forms/test_autocompleteinfo.html +++ b/dom/html/test/forms/test_autocompleteinfo.html @@ -44,14 +44,6 @@ var values = [ ["tel-extension", {fieldName: "tel-extension"}, ""], ["foobar", {}, ""], ["section-blue", {}, ""], - [" WEBAUTHN ", {fieldName: "webauthn", credentialType: "webauthn"}, "webauthn"], - - // One token + WebAuthn credential type - ["on webauthn", {}, ""], - ["off webauthn", {}, ""], - ["webauthn webauthn", {}, ""], - ["username WebAuthn", {fieldName: "username", credentialType: "webauthn"}, "username webauthn"], - ["current-PASSWORD webauthn", {fieldName: "current-password", credentialType: "webauthn", canAutomaticallyPersist: false}, "current-password webauthn"], // Two tokens ["on off", {}, ""], @@ -75,11 +67,6 @@ var values = [ ["fax url", {}, ""], ["section-blue name", {section: "section-blue", fieldName: "name"}, "section-blue name"], ["section-blue tel", {section: "section-blue", fieldName: "tel"}, "section-blue tel"], - ["webauthn username", {}, ""], - - // Two tokens + WebAuthn credential type - ["fax url webauthn", {}, ""], - ["shipping tel webauthn", {addressType: "shipping", fieldName: "tel", credentialType: "webauthn"}, "shipping tel webauthn"], // Three tokens ["billing invalid tel", {}, ""], @@ -95,11 +82,6 @@ var values = [ ["section-blue home address-level2", {}, ""], ["section-blue shipping name", {section: "section-blue", addressType: "shipping", fieldName: "name"}, "section-blue shipping name"], ["section-blue mobile tel", {section: "section-blue", contactType: "mobile", fieldName: "tel"}, "section-blue mobile tel"], - ["shipping webauthn tel", {}, ""], - - // Three tokens + WebAuthn credential type - ["invalid mobile tel webauthn", {}, ""], - ["section-blue shipping name webauthn", {section: "section-blue", addressType: "shipping", fieldName: "name", credentialType: "webauthn"}, "section-blue shipping name webauthn"], // Four tokens ["billing billing mobile tel", {}, ""], @@ -107,19 +89,10 @@ var values = [ ["secti shipping work address-line1", {}, ""], ["section-blue shipping home name", {}, ""], ["section-blue shipping mobile tel", {section: "section-blue", addressType: "shipping", contactType: "mobile", fieldName: "tel"}, "section-blue shipping mobile tel"], - ["section-blue webauthn mobile tel", {}, ""], - - // Four tokens + WebAuthn credential type - ["section-blue shipping home name webauthn", {}, ""], - ["section-blue shipping mobile tel webauthn", {section: "section-blue", addressType: "shipping", contactType: "mobile", fieldName: "tel", credentialType: "webauthn"}, "section-blue shipping mobile tel webauthn"], // Five tokens (invalid) ["billing billing billing mobile tel", {}, ""], ["section-blue section-blue billing mobile tel", {}, ""], - ["section-blue section-blue billing webauthn tel", {}, ""], - - // Five tokens + WebAuthn credential type (invalid) - ["billing billing billing mobile tel webauthn", {}, ""], ]; var autocompleteInfoFieldIds = ["input", "select"]; @@ -170,8 +143,6 @@ function testAutocompleteInfoValue(aEnabled) { "Checking autocompleteInfo.contactType for " + field + ": " + test[0]); is(info.fieldName, "fieldName" in test[1] ? test[1].fieldName : "", "Checking autocompleteInfo.fieldName for " + field + ": " + test[0]); - is(info.credentialType, "credentialType" in test[1] ? test[1].credentialType: "", - "Checking autocompleteInfo.credentialType for " + field + ": " + test[0]); is(info.canAutomaticallyPersist, "canAutomaticallyPersist" in test[1] ? test[1].canAutomaticallyPersist : true, "Checking autocompleteInfo.canAutomaticallyPersist for " + field + ": " + test[0]); } diff --git a/dom/webauthn/AndroidWebAuthnService.cpp b/dom/webauthn/AndroidWebAuthnService.cpp index ea2c19736e6a..3862275e49ab 100644 --- a/dom/webauthn/AndroidWebAuthnService.cpp +++ b/dom/webauthn/AndroidWebAuthnService.cpp @@ -40,7 +40,7 @@ AndroidWebAuthnService::GetIsUVPAA(bool* aAvailable) { NS_IMETHODIMP AndroidWebAuthnService::MakeCredential(uint64_t aTransactionId, - uint64_t aBrowsingContextId, + uint64_t browsingContextId, nsIWebAuthnRegisterArgs* aArgs, nsIWebAuthnRegisterPromise* aPromise) { Reset(); @@ -201,18 +201,11 @@ AndroidWebAuthnService::MakeCredential(uint64_t aTransactionId, NS_IMETHODIMP AndroidWebAuthnService::GetAssertion(uint64_t aTransactionId, - uint64_t aBrowsingContextId, + uint64_t browsingContextId, nsIWebAuthnSignArgs* aArgs, nsIWebAuthnSignPromise* aPromise) { Reset(); - bool conditionallyMediated; - Unused << aArgs->GetConditionallyMediated(&conditionallyMediated); - if (conditionallyMediated) { - aPromise->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return NS_OK; - } - GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( "java::WebAuthnTokenManager::WebAuthnGetAssertion", [self = RefPtr{this}, aArgs = RefPtr{aArgs}, @@ -306,8 +299,7 @@ AndroidWebAuthnService::GetAssertion(uint64_t aTransactionId, NS_IMETHODIMP AndroidWebAuthnService::Reset() { - mRegisterCredPropsRk.reset(); - + mRegisterCredPropsRk = Nothing(); return NS_OK; } @@ -316,34 +308,6 @@ AndroidWebAuthnService::Cancel(uint64_t aTransactionId) { return NS_ERROR_NOT_IMPLEMENTED; } -NS_IMETHODIMP -AndroidWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId, - const nsAString& aOrigin, - uint64_t* aRv) { - // Signal that there is no pending conditional get request, so the caller - // will not attempt to call GetAutoFillEntries, SelectAutoFillEntry, or - // ResumeConditionalGet (as these are not implemented). - *aRv = 0; - return NS_OK; -} - -NS_IMETHODIMP -AndroidWebAuthnService::GetAutoFillEntries( - uint64_t aTransactionId, nsTArray>& aRv) { - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -AndroidWebAuthnService::SelectAutoFillEntry( - uint64_t aTransactionId, const nsTArray& aCredentialId) { - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -AndroidWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) { - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP AndroidWebAuthnService::PinCallback(uint64_t aTransactionId, const nsACString& aPin) { diff --git a/dom/webauthn/MacOSWebAuthnService.mm b/dom/webauthn/MacOSWebAuthnService.mm index f8457505115e..13973bb1ec8c 100644 --- a/dom/webauthn/MacOSWebAuthnService.mm +++ b/dom/webauthn/MacOSWebAuthnService.mm @@ -846,34 +846,6 @@ MacOSWebAuthnService::Cancel(uint64_t aTransactionId) { return NS_ERROR_NOT_IMPLEMENTED; } -NS_IMETHODIMP -MacOSWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId, - const nsAString& aOrigin, - uint64_t* aRv) { - // Signal that there is no pending conditional get request, so the caller - // will not attempt to call GetAutoFillEntries, SelectAutoFillEntry, or - // ResumeConditionalGet (as these are not implemented). - *aRv = 0; - return NS_OK; -} - -NS_IMETHODIMP -MacOSWebAuthnService::GetAutoFillEntries( - uint64_t aTransactionId, nsTArray>& aRv) { - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -MacOSWebAuthnService::SelectAutoFillEntry( - uint64_t aTransactionId, const nsTArray& aCredentialId) { - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -MacOSWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) { - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP MacOSWebAuthnService::PinCallback(uint64_t aTransactionId, const nsACString& aPin) { diff --git a/dom/webauthn/PWebAuthnTransaction.ipdl b/dom/webauthn/PWebAuthnTransaction.ipdl index 229fb7899d1e..f9d59209dbc1 100644 --- a/dom/webauthn/PWebAuthnTransaction.ipdl +++ b/dom/webauthn/PWebAuthnTransaction.ipdl @@ -121,7 +121,6 @@ struct WebAuthnGetAssertionInfo { WebAuthnScopedCredential[] AllowList; WebAuthnExtension[] Extensions; nsString userVerificationRequirement; - bool ConditionallyMediated; uint64_t BrowsingContextId; }; diff --git a/dom/webauthn/PublicKeyCredential.cpp b/dom/webauthn/PublicKeyCredential.cpp index a77c1ee5a3d8..fd0d206dd181 100644 --- a/dom/webauthn/PublicKeyCredential.cpp +++ b/dom/webauthn/PublicKeyCredential.cpp @@ -138,12 +138,8 @@ already_AddRefed PublicKeyCredential::IsConditionalMediationAvailable( if (aError.Failed()) { return nullptr; } -#if defined(MOZ_WIDGET_ANDROID) + // Support for conditional mediation will be added in Bug 1838932 promise->MaybeResolve(false); -#else - promise->MaybeResolve( - StaticPrefs::security_webauthn_enable_conditional_mediation()); -#endif return promise.forget(); } diff --git a/dom/webauthn/WebAuthnArgs.cpp b/dom/webauthn/WebAuthnArgs.cpp index 7c78d39beff1..94cffc8dc63e 100644 --- a/dom/webauthn/WebAuthnArgs.cpp +++ b/dom/webauthn/WebAuthnArgs.cpp @@ -248,10 +248,4 @@ WebAuthnSignArgs::GetTimeoutMS(uint32_t* aTimeoutMS) { return NS_OK; } -NS_IMETHODIMP -WebAuthnSignArgs::GetConditionallyMediated(bool* aConditionallyMediated) { - *aConditionallyMediated = mInfo.ConditionallyMediated(); - return NS_OK; -} - } // namespace mozilla::dom diff --git a/dom/webauthn/WebAuthnAutoFillEntry.cpp b/dom/webauthn/WebAuthnAutoFillEntry.cpp deleted file mode 100644 index 78423d1df20d..000000000000 --- a/dom/webauthn/WebAuthnAutoFillEntry.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WebAuthnAutoFillEntry.h" - -namespace mozilla::dom { - -NS_IMPL_ISUPPORTS(WebAuthnAutoFillEntry, nsIWebAuthnAutoFillEntry) - -NS_IMETHODIMP -WebAuthnAutoFillEntry::GetProvider(uint8_t* aProvider) { - *aProvider = mProvider; - return NS_OK; -} - -NS_IMETHODIMP -WebAuthnAutoFillEntry::GetUserName(nsAString& aUserName) { - aUserName.Assign(mUserName); - return NS_OK; -} - -NS_IMETHODIMP -WebAuthnAutoFillEntry::GetRpId(nsAString& aRpId) { - aRpId.Assign(mRpId); - return NS_OK; -} - -NS_IMETHODIMP -WebAuthnAutoFillEntry::GetCredentialId(nsTArray& aCredentialId) { - aCredentialId.Assign(mCredentialId); - return NS_OK; -} - -} // namespace mozilla::dom diff --git a/dom/webauthn/WebAuthnAutoFillEntry.h b/dom/webauthn/WebAuthnAutoFillEntry.h deleted file mode 100644 index 53fb0405623d..000000000000 --- a/dom/webauthn/WebAuthnAutoFillEntry.h +++ /dev/null @@ -1,51 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_WebAuthnAutoFillEntry_h_ -#define mozilla_dom_WebAuthnAutoFillEntry_h_ - -#include "nsIWebAuthnService.h" -#include "nsString.h" - -#ifdef XP_WIN -# include -# include "winwebauthn/webauthn.h" -#endif - -namespace mozilla::dom { - -class WebAuthnAutoFillEntry final : public nsIWebAuthnAutoFillEntry { - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIWEBAUTHNAUTOFILLENTRY - - WebAuthnAutoFillEntry(uint8_t aProvider, const nsAString& aUserName, - const nsAString& aRpId, - const nsTArray& aCredentialId) - : mProvider(aProvider), mUserName(aUserName), mRpId(aRpId) { - mCredentialId.Assign(aCredentialId); - } - -#ifdef XP_WIN - explicit WebAuthnAutoFillEntry( - PCWEBAUTHN_CREDENTIAL_DETAILS aCredentialDetails) { - mProvider = nsIWebAuthnAutoFillEntry::PROVIDER_PLATFORM_WINDOWS; - mUserName.Assign(aCredentialDetails->pUserInformation->pwszName); - mRpId.Assign(aCredentialDetails->pRpInformation->pwszId); - mCredentialId.AppendElements(aCredentialDetails->pbCredentialID, - aCredentialDetails->cbCredentialID); - } -#endif - - private: - ~WebAuthnAutoFillEntry() = default; - - uint8_t mProvider; - nsString mUserName; - nsString mRpId; - nsTArray mCredentialId; -}; - -} // namespace mozilla::dom -#endif // mozilla_dom_WebAuthnAutoFillEntry_h_ diff --git a/dom/webauthn/WebAuthnManager.cpp b/dom/webauthn/WebAuthnManager.cpp index ec28e614af26..e7282b8a5cbb 100644 --- a/dom/webauthn/WebAuthnManager.cpp +++ b/dom/webauthn/WebAuthnManager.cpp @@ -486,7 +486,6 @@ const size_t MAX_ALLOWED_CREDENTIALS = 20; already_AddRefed WebAuthnManager::GetAssertion( const PublicKeyCredentialRequestOptions& aOptions, - const bool aConditionallyMediated, const Optional>& aSignal, ErrorResult& aError) { MOZ_ASSERT(NS_IsMainThread()); @@ -672,7 +671,7 @@ already_AddRefed WebAuthnManager::GetAssertion( WebAuthnGetAssertionInfo info(origin, NS_ConvertUTF8toUTF16(rpId), challenge, clientDataJSON, adjustedTimeout, allowList, extensions, aOptions.mUserVerification, - aConditionallyMediated, context->Top()->Id()); + context->Top()->Id()); // Set up the transaction state (including event listeners, etc). Fallible // operations should not be performed below this line, as we must not leave diff --git a/dom/webauthn/WebAuthnManager.h b/dom/webauthn/WebAuthnManager.h index 10f0f511232d..9101830638ea 100644 --- a/dom/webauthn/WebAuthnManager.h +++ b/dom/webauthn/WebAuthnManager.h @@ -93,7 +93,6 @@ class WebAuthnManager final : public WebAuthnManagerBase, public AbortFollower { already_AddRefed GetAssertion( const PublicKeyCredentialRequestOptions& aOptions, - const bool aConditionallyMediated, const Optional>& aSignal, ErrorResult& aError); already_AddRefed Store(const Credential& aCredential, diff --git a/dom/webauthn/WebAuthnService.cpp b/dom/webauthn/WebAuthnService.cpp index ff5b5752c5f6..70879f256cfa 100644 --- a/dom/webauthn/WebAuthnService.cpp +++ b/dom/webauthn/WebAuthnService.cpp @@ -2,10 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/Services.h" #include "mozilla/StaticPrefs_security.h" -#include "nsIObserverService.h" -#include "nsThreadUtils.h" #include "WebAuthnService.h" namespace mozilla::dom { @@ -35,35 +32,12 @@ WebAuthnService::GetAssertion(uint64_t aTransactionId, uint64_t browsingContextId, nsIWebAuthnSignArgs* aArgs, nsIWebAuthnSignPromise* aPromise) { - nsresult rv; if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { - rv = mTestService->GetAssertion(aTransactionId, browsingContextId, aArgs, - aPromise); - } else { - rv = mPlatformService->GetAssertion(aTransactionId, browsingContextId, + return mTestService->GetAssertion(aTransactionId, browsingContextId, aArgs, + aPromise); + } + return mPlatformService->GetAssertion(aTransactionId, browsingContextId, aArgs, aPromise); - } - - if (NS_FAILED(rv)) { - return rv; - } - - // If this is a conditionally mediated request, notify observers that there - // is a pending transaction. This is mainly useful in tests. - bool conditionallyMediated; - Unused << aArgs->GetConditionallyMediated(&conditionallyMediated); - if (conditionallyMediated) { - nsCOMPtr runnable(NS_NewRunnableFunction(__func__, []() { - nsCOMPtr os = mozilla::services::GetObserverService(); - if (os) { - os->NotifyObservers(nullptr, "webauthn:conditional-get-pending", - nullptr); - } - })); - NS_DispatchToMainThread(runnable.forget()); - } - - return NS_OK; } NS_IMETHODIMP @@ -74,44 +48,6 @@ WebAuthnService::GetIsUVPAA(bool* aAvailable) { return mPlatformService->GetIsUVPAA(aAvailable); } -NS_IMETHODIMP -WebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId, - const nsAString& aOrigin, - uint64_t* aRv) { - if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { - return mTestService->HasPendingConditionalGet(aBrowsingContextId, aOrigin, - aRv); - } - return mPlatformService->HasPendingConditionalGet(aBrowsingContextId, aOrigin, - aRv); -} - -NS_IMETHODIMP -WebAuthnService::GetAutoFillEntries( - uint64_t aTransactionId, nsTArray>& aRv) { - if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { - return mTestService->GetAutoFillEntries(aTransactionId, aRv); - } - return mPlatformService->GetAutoFillEntries(aTransactionId, aRv); -} - -NS_IMETHODIMP -WebAuthnService::SelectAutoFillEntry(uint64_t aTransactionId, - const nsTArray& aCredentialId) { - if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { - return mTestService->SelectAutoFillEntry(aTransactionId, aCredentialId); - } - return mPlatformService->SelectAutoFillEntry(aTransactionId, aCredentialId); -} - -NS_IMETHODIMP -WebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) { - if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { - return mTestService->ResumeConditionalGet(aTransactionId); - } - return mPlatformService->ResumeConditionalGet(aTransactionId); -} - NS_IMETHODIMP WebAuthnService::Reset() { if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { diff --git a/dom/webauthn/WinWebAuthnService.cpp b/dom/webauthn/WinWebAuthnService.cpp index c0e1804b3a85..a64bcca235a9 100644 --- a/dom/webauthn/WinWebAuthnService.cpp +++ b/dom/webauthn/WinWebAuthnService.cpp @@ -44,10 +44,6 @@ static decltype(WebAuthNCancelCurrentOperation)* static decltype(WebAuthNGetErrorName)* gWinWebauthnGetErrorName = nullptr; static decltype(WebAuthNGetApiVersionNumber)* gWinWebauthnGetApiVersionNumber = nullptr; -static decltype(WebAuthNGetPlatformCredentialList)* - gWinWebauthnGetPlatformCredentialList = nullptr; -static decltype(WebAuthNFreePlatformCredentialList)* - gWinWebauthnFreePlatformCredentialList = nullptr; } // namespace @@ -62,7 +58,7 @@ NS_IMPL_ISUPPORTS(WinWebAuthnService, nsIWebAuthnService) /* static */ nsresult WinWebAuthnService::EnsureWinWebAuthnModuleLoaded() { { - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + StaticAutoReadLock lock(gWinWebAuthnModuleLock); if (gWinWebAuthnModule) { // The module is already loaded. return NS_OK; @@ -135,21 +131,6 @@ nsresult WinWebAuthnService::EnsureWinWebAuthnModuleLoaded() { return NS_ERROR_NOT_AVAILABLE; } - if (gWinWebauthnGetApiVersionNumber() >= WEBAUTHN_API_VERSION_4) { - gWinWebauthnGetPlatformCredentialList = - reinterpret_cast( - GetProcAddress(gWinWebAuthnModule, - "WebAuthNGetPlatformCredentialList")); - gWinWebauthnFreePlatformCredentialList = - reinterpret_cast( - GetProcAddress(gWinWebAuthnModule, - "WebAuthNFreePlatformCredentialList")); - if (!(gWinWebauthnGetPlatformCredentialList && - gWinWebauthnFreePlatformCredentialList)) { - return NS_ERROR_NOT_AVAILABLE; - } - } - markModuleUnusable.release(); return NS_OK; } @@ -167,7 +148,7 @@ bool WinWebAuthnService::AreWebAuthNApisAvailable() { nsresult rv = EnsureWinWebAuthnModuleLoaded(); NS_ENSURE_SUCCESS(rv, false); - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + StaticAutoReadLock lock(gWinWebAuthnModuleLock); return gWinWebAuthnModule && gWinWebauthnGetApiVersionNumber() >= kMinWinWebAuthNApiVersion; } @@ -179,7 +160,7 @@ WinWebAuthnService::GetIsUVPAA(bool* aAvailable) { if (WinWebAuthnService::AreWebAuthNApisAvailable()) { BOOL isUVPAA = FALSE; - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + StaticAutoReadLock lock(gWinWebAuthnModuleLock); *aAvailable = gWinWebAuthnModule && gWinWebauthnIsUVPAA(&isUVPAA) == S_OK && isUVPAA == TRUE; } else { @@ -197,20 +178,12 @@ NS_IMETHODIMP WinWebAuthnService::Reset() { // Reset will never be the first function to use gWinWebAuthnModule, so // we shouldn't try to initialize it here. - auto guard = mTransactionState.Lock(); - if (guard->isSome()) { - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + if (mTransactionId.isSome()) { + StaticAutoReadLock lock(gWinWebAuthnModuleLock); if (gWinWebAuthnModule) { - const GUID cancellationId = guard->ref().cancellationId; - gWinWebauthnCancelCurrentOperation(&cancellationId); + gWinWebauthnCancelCurrentOperation(&mCancellationId); } - if (guard->ref().pendingSignPromise.isSome()) { - // This request was never dispatched to the platform API, so - // we need to reject the promise ourselves. - guard->ref().pendingSignPromise.ref()->Reject( - NS_ERROR_DOM_NOT_ALLOWED_ERR); - } - guard->reset(); + mTransactionId.reset(); } return NS_OK; @@ -218,37 +191,31 @@ WinWebAuthnService::Reset() { NS_IMETHODIMP WinWebAuthnService::MakeCredential(uint64_t aTransactionId, - uint64_t aBrowsingContextId, + uint64_t browsingContextId, nsIWebAuthnRegisterArgs* aArgs, nsIWebAuthnRegisterPromise* aPromise) { nsresult rv = EnsureWinWebAuthnModuleLoaded(); NS_ENSURE_SUCCESS(rv, rv); Reset(); - auto guard = mTransactionState.Lock(); - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); - GUID cancellationId; - if (gWinWebauthnGetCancellationId(&cancellationId) != S_OK) { - // caller will reject promise - return NS_ERROR_DOM_UNKNOWN_ERR; + mTransactionId = Some(aTransactionId); + { + StaticAutoReadLock lock(gWinWebAuthnModuleLock); + if (gWinWebauthnGetCancellationId(&mCancellationId) != S_OK) { + // caller will reject promise + return NS_ERROR_DOM_UNKNOWN_ERR; + } } - *guard = Some(TransactionState{ - aTransactionId, - aBrowsingContextId, - Nothing(), - Nothing(), - cancellationId, - }); nsCOMPtr runnable(NS_NewRunnableFunction( "WinWebAuthnService::MakeCredential", [self = RefPtr{this}, aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise}, - cancellationId]() mutable { + aCancellationId = mCancellationId]() mutable { // Take a read lock on gWinWebAuthnModuleLock to prevent the module from // being unloaded while the operation is in progress. This does not // prevent the operation from being cancelled, so it does not block a // clean shutdown. - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + StaticAutoReadLock lock(gWinWebAuthnModuleLock); if (!gWinWebAuthnModule) { aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR); return; @@ -516,8 +483,8 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId, winRequireResidentKey, winUserVerificationReq, winAttestation, - 0, // Flags - &cancellationId, // CancellationId + 0, // Flags + &aCancellationId, // CancellationId pExcludeCredentialList, WEBAUTHN_ENTERPRISE_ATTESTATION_NONE, WEBAUTHN_LARGE_BLOB_SUPPORT_NONE, @@ -595,65 +562,31 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId, NS_IMETHODIMP WinWebAuthnService::GetAssertion(uint64_t aTransactionId, - uint64_t aBrowsingContextId, + uint64_t browsingContextId, nsIWebAuthnSignArgs* aArgs, nsIWebAuthnSignPromise* aPromise) { nsresult rv = EnsureWinWebAuthnModuleLoaded(); NS_ENSURE_SUCCESS(rv, rv); Reset(); - - auto guard = mTransactionState.Lock(); - - GUID cancellationId; + mTransactionId = Some(aTransactionId); { - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); - if (gWinWebauthnGetCancellationId(&cancellationId) != S_OK) { + StaticAutoReadLock lock(gWinWebAuthnModuleLock); + if (gWinWebauthnGetCancellationId(&mCancellationId) != S_OK) { // caller will reject promise return NS_ERROR_DOM_UNKNOWN_ERR; } } - *guard = Some(TransactionState{ - aTransactionId, - aBrowsingContextId, - Some(RefPtr{aArgs}), - Some(RefPtr{aPromise}), - cancellationId, - }); - - bool conditionallyMediated; - Unused << aArgs->GetConditionallyMediated(&conditionallyMediated); - if (!conditionallyMediated) { - DoGetAssertion(Nothing(), guard); - } - return NS_OK; -} - -void WinWebAuthnService::DoGetAssertion( - Maybe>&& aSelectedCredentialId, - const TransactionStateMutex::AutoLock& aGuard) { - if (aGuard->isNothing() || aGuard->ref().pendingSignArgs.isNothing() || - aGuard->ref().pendingSignPromise.isNothing()) { - return; - } - - // Take the pending Args and Promise to prevent repeated calls to - // DoGetAssertion for this transaction. - RefPtr aArgs = aGuard->ref().pendingSignArgs.extract(); - RefPtr aPromise = - aGuard->ref().pendingSignPromise.extract(); - nsCOMPtr runnable(NS_NewRunnableFunction( "WinWebAuthnService::MakeCredential", - [self = RefPtr{this}, aArgs, aPromise, - aSelectedCredentialId = std::move(aSelectedCredentialId), - aCancellationId = aGuard->ref().cancellationId]() mutable { + [self = RefPtr{this}, aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise}, + aCancellationId = mCancellationId]() mutable { // Take a read lock on gWinWebAuthnModuleLock to prevent the module from // being unloaded while the operation is in progress. This does not // prevent the operation from being cancelled, so it does not block a // clean shutdown. - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); + StaticAutoReadLock lock(gWinWebAuthnModuleLock); if (!gWinWebAuthnModule) { aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR); return; @@ -715,15 +648,10 @@ void WinWebAuthnService::DoGetAssertion( // allow Credentials nsTArray> allowList; + Unused << aArgs->GetAllowList(allowList); + nsTArray allowListTransports; - if (aSelectedCredentialId.isSome()) { - allowList.AppendElement(aSelectedCredentialId.extract()); - allowListTransports.AppendElement( - MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL); - } else { - Unused << aArgs->GetAllowList(allowList); - Unused << aArgs->GetAllowListTransports(allowListTransports); - } + Unused << aArgs->GetAllowListTransports(allowListTransports); if (allowList.Length() != allowListTransports.Length()) { aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR); @@ -838,115 +766,6 @@ void WinWebAuthnService::DoGetAssertion( })); NS_DispatchBackgroundTask(runnable, NS_DISPATCH_EVENT_MAY_BLOCK); -} - -NS_IMETHODIMP -WinWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId, - const nsAString& aOrigin, - uint64_t* aRv) { - auto guard = mTransactionState.Lock(); - if (guard->isNothing() || - guard->ref().browsingContextId != aBrowsingContextId || - guard->ref().pendingSignArgs.isNothing()) { - *aRv = 0; - return NS_OK; - } - - nsString origin; - Unused << guard->ref().pendingSignArgs.ref()->GetOrigin(origin); - if (origin != aOrigin) { - *aRv = 0; - return NS_OK; - } - - *aRv = guard->ref().transactionId; - return NS_OK; -} - -NS_IMETHODIMP -WinWebAuthnService::GetAutoFillEntries( - uint64_t aTransactionId, nsTArray>& aRv) { - auto guard = mTransactionState.Lock(); - if (guard->isNothing() || guard->ref().transactionId != aTransactionId || - guard->ref().pendingSignArgs.isNothing()) { - return NS_ERROR_NOT_AVAILABLE; - } - - StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock); - if (!gWinWebAuthnModule) { - return NS_ERROR_NOT_AVAILABLE; - } - - aRv.Clear(); - - if (gWinWebauthnGetApiVersionNumber() < WEBAUTHN_API_VERSION_4) { - // GetPlatformCredentialList was added in version 4. Earlier versions - // can still present a generic "Use a Passkey" autofill entry, so - // this isn't an error. - return NS_OK; - } - - nsString rpId; - Unused << guard->ref().pendingSignArgs.ref()->GetRpId(rpId); - - WEBAUTHN_GET_CREDENTIALS_OPTIONS getCredentialsOptions{ - WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1, - rpId.get(), // pwszRpId - FALSE, // bBrowserInPrivateMode - }; - PWEBAUTHN_CREDENTIAL_DETAILS_LIST pCredentialList = nullptr; - HRESULT hr = gWinWebauthnGetPlatformCredentialList(&getCredentialsOptions, - &pCredentialList); - // WebAuthNGetPlatformCredentialList has an _Outptr_result_maybenull_ - // annotation and a comment "Returns NTE_NOT_FOUND when credentials are - // not found." - if (pCredentialList == nullptr) { - if (hr != NTE_NOT_FOUND) { - return NS_ERROR_FAILURE; - } - return NS_OK; - } - MOZ_ASSERT(hr == S_OK); - for (size_t i = 0; i < pCredentialList->cCredentialDetails; i++) { - RefPtr entry( - new WebAuthnAutoFillEntry(pCredentialList->ppCredentialDetails[i])); - aRv.AppendElement(entry); - } - gWinWebauthnFreePlatformCredentialList(pCredentialList); - return NS_OK; -} - -NS_IMETHODIMP -WinWebAuthnService::SelectAutoFillEntry( - uint64_t aTransactionId, const nsTArray& aCredentialId) { - auto guard = mTransactionState.Lock(); - if (guard->isNothing() || guard->ref().transactionId != aTransactionId || - guard->ref().pendingSignArgs.isNothing()) { - return NS_ERROR_NOT_AVAILABLE; - } - - nsTArray> allowList; - Unused << guard->ref().pendingSignArgs.ref()->GetAllowList(allowList); - if (!allowList.IsEmpty() && !allowList.Contains(aCredentialId)) { - return NS_ERROR_FAILURE; - } - - Maybe> id; - id.emplace(); - id.ref().Assign(aCredentialId); - DoGetAssertion(std::move(id), guard); - - return NS_OK; -} - -NS_IMETHODIMP -WinWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) { - auto guard = mTransactionState.Lock(); - if (guard->isNothing() || guard->ref().transactionId != aTransactionId || - guard->ref().pendingSignArgs.isNothing()) { - return NS_ERROR_NOT_AVAILABLE; - } - DoGetAssertion(Nothing(), guard); return NS_OK; } diff --git a/dom/webauthn/WinWebAuthnService.h b/dom/webauthn/WinWebAuthnService.h index 8312ae83e1a8..99e6a20ac937 100644 --- a/dom/webauthn/WinWebAuthnService.h +++ b/dom/webauthn/WinWebAuthnService.h @@ -22,26 +22,15 @@ class WinWebAuthnService final : public nsIWebAuthnService { static bool AreWebAuthNApisAvailable(); static nsresult EnsureWinWebAuthnModuleLoaded(); - WinWebAuthnService() - : mTransactionState(Nothing(), "WinWebAuthnService::mTransactionState"){}; + WinWebAuthnService() = default; private: ~WinWebAuthnService(); uint32_t GetWebAuthNApiVersion(); - struct TransactionState { - uint64_t transactionId; - uint64_t browsingContextId; - Maybe> pendingSignArgs; - Maybe> pendingSignPromise; - GUID cancellationId; - }; - - using TransactionStateMutex = DataMutex>; - TransactionStateMutex mTransactionState; - void DoGetAssertion(Maybe>&& aSelectedCredentialId, - const TransactionStateMutex::AutoLock& aGuard); + Maybe mTransactionId; + GUID mCancellationId; }; } // namespace mozilla::dom diff --git a/dom/webauthn/authrs_bridge/src/lib.rs b/dom/webauthn/authrs_bridge/src/lib.rs index 6283a4e54bc5..69045a00d742 100644 --- a/dom/webauthn/authrs_bridge/src/lib.rs +++ b/dom/webauthn/authrs_bridge/src/lib.rs @@ -37,12 +37,12 @@ use serde_cbor; use serde_json::json; use std::fmt::Write; use std::sync::mpsc::{channel, Receiver, RecvError, Sender}; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; use thin_vec::{thin_vec, ThinVec}; use xpcom::interfaces::{ - nsICredentialParameters, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnAutoFillEntry, - nsIWebAuthnRegisterArgs, nsIWebAuthnRegisterPromise, nsIWebAuthnRegisterResult, - nsIWebAuthnService, nsIWebAuthnSignArgs, nsIWebAuthnSignPromise, nsIWebAuthnSignResult, + nsICredentialParameters, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnRegisterArgs, + nsIWebAuthnRegisterPromise, nsIWebAuthnRegisterResult, nsIWebAuthnService, nsIWebAuthnSignArgs, + nsIWebAuthnSignPromise, nsIWebAuthnSignResult, }; use xpcom::{xpcom_method, RefPtr}; mod about_webauthn_controller; @@ -542,7 +542,8 @@ impl TransactionPromise { enum TransactionArgs { Register(/* timeout */ u64, RegisterArgs), - Sign(/* timeout */ u64, SignArgs), + // Bug 1838932 - we'll need to cache SignArgs once we support conditional mediation + // Sign(/* timeout */ u64, SignArgs), } struct TransactionState { @@ -763,9 +764,9 @@ impl AuthrsService { browsing_context_id, pending_args: Some(TransactionArgs::Register(timeout_ms as u64, info)), promise: TransactionPromise::Register(promise), + interactive_receiver: None, pin_receiver: None, selection_receiver: None, - interactive_receiver: None, puat_cache: None, }); @@ -915,8 +916,8 @@ impl AuthrsService { let mut allow_list = ThinVec::new(); unsafe { args.GetAllowList(&mut allow_list) }.to_result()?; - let allow_list = allow_list - .iter() + let allow_list: Vec<_> = allow_list + .iter_mut() .map(|id| PublicKeyCredentialDescriptor { id: id.to_vec(), transports: vec![], @@ -940,79 +941,9 @@ impl AuthrsService { _ => (), } - let mut conditionally_mediated = false; - unsafe { args.GetConditionallyMediated(&mut conditionally_mediated) }.to_result()?; - - let info = SignArgs { - client_data_hash: client_data_hash_arr, - relying_party_id: relying_party_id.to_string(), - origin: origin.to_string(), - allow_list, - user_verification_req, - user_presence_req: true, - extensions: AuthenticationExtensionsClientInputs { - app_id, - ..Default::default() - }, - pin: None, - use_ctap1_fallback: !static_prefs::pref!("security.webauthn.ctap2"), - }; - - let mut guard = self.transaction.lock().unwrap(); - *guard = Some(TransactionState { - tid, - browsing_context_id, - pending_args: Some(TransactionArgs::Sign(timeout_ms as u64, info)), - promise: TransactionPromise::Sign(promise), - pin_receiver: None, - selection_receiver: None, - interactive_receiver: None, - puat_cache: None, - }); - - if !conditionally_mediated { - // Immediately proceed to the modal UI flow. - self.do_get_assertion(None, guard) - } else { - // Cache the request and wait for the conditional UI to request autofill entries, etc. - Ok(()) - } - } - - fn do_get_assertion( - &self, - mut selected_credential_id: Option>, - mut guard: MutexGuard>, - ) -> Result<(), nsresult> { - let Some(state) = guard.as_mut() else { - return Err(NS_ERROR_FAILURE); - }; - let browsing_context_id = state.browsing_context_id; - let tid = state.tid; - let (timeout_ms, mut info) = match state.pending_args.take() { - Some(TransactionArgs::Sign(timeout_ms, info)) => (timeout_ms, info), - _ => return Err(NS_ERROR_FAILURE), - }; - - if let Some(id) = selected_credential_id.take() { - if info.allow_list.is_empty() { - info.allow_list.push(PublicKeyCredentialDescriptor { - id, - transports: vec![], - }); - } else { - // We need to ensure that the selected credential id - // was in the original allow_list. - info.allow_list.retain(|cred| cred.id == id); - if info.allow_list.is_empty() { - return Err(NS_ERROR_FAILURE); - } - } - } - let (status_tx, status_rx) = channel::(); let status_transaction = self.transaction.clone(); - let status_origin = info.origin.to_string(); + let status_origin = origin.to_string(); RunnableBuilder::new("AuthrsService::GetAssertion::StatusReceiver", move || { let _ = status_callback( status_rx, @@ -1025,8 +956,8 @@ impl AuthrsService { .may_block(true) .dispatch_background_task()?; - let uniq_allowed_cred = if info.allow_list.len() == 1 { - info.allow_list.first().cloned() + let uniq_allowed_cred = if allow_list.len() == 1 { + allow_list.first().cloned() } else { None }; @@ -1062,6 +993,21 @@ impl AuthrsService { }), ); + let info = SignArgs { + client_data_hash: client_data_hash_arr, + relying_party_id: relying_party_id.to_string(), + origin: origin.to_string(), + allow_list, + user_verification_req, + user_presence_req: true, + extensions: AuthenticationExtensionsClientInputs { + app_id, + ..Default::default() + }, + pin: None, + use_ctap1_fallback: !static_prefs::pref!("security.webauthn.ctap2"), + }; + // TODO(Bug 1855290) Remove this presence prompt send_prompt( BrowserPromptType::Presence, @@ -1070,6 +1016,17 @@ impl AuthrsService { Some(browsing_context_id), )?; + *self.transaction.lock().unwrap() = Some(TransactionState { + tid, + browsing_context_id, + pending_args: None, + promise: TransactionPromise::Sign(promise), + interactive_receiver: None, + pin_receiver: None, + selection_receiver: None, + puat_cache: None, + }); + // As in `register`, we are intentionally avoiding `AuthenticatorService` here. if static_prefs::pref!("security.webauth.webauthn_enable_usbtoken") { self.usb_token_manager.lock().unwrap().sign( @@ -1088,79 +1045,6 @@ impl AuthrsService { Ok(()) } - xpcom_method!(has_pending_conditional_get => HasPendingConditionalGet(aBrowsingContextId: u64, aOrigin: *const nsAString) -> u64); - fn has_pending_conditional_get( - &self, - browsing_context_id: u64, - origin: &nsAString, - ) -> Result { - let mut guard = self.transaction.lock().unwrap(); - let Some(state) = guard.as_mut() else { - return Ok(0); - }; - let Some(TransactionArgs::Sign(_, info)) = state.pending_args.as_ref() else { - return Ok(0); - }; - if state.browsing_context_id != browsing_context_id { - return Ok(0); - } - if !info.origin.eq(&origin.to_string()) { - return Ok(0); - } - Ok(state.tid) - } - - xpcom_method!(get_autofill_entries => GetAutoFillEntries(aTransactionId: u64) -> ThinVec>>); - fn get_autofill_entries( - &self, - tid: u64, - ) -> Result>>, nsresult> { - let mut guard = self.transaction.lock().unwrap(); - let Some(state) = guard.as_mut() else { - return Err(NS_ERROR_NOT_AVAILABLE); - }; - if state.tid != tid { - return Err(NS_ERROR_NOT_AVAILABLE); - } - let Some(TransactionArgs::Sign(_, info)) = state.pending_args.as_ref() else { - return Err(NS_ERROR_NOT_AVAILABLE); - }; - if static_prefs::pref!("security.webauth.webauthn_enable_usbtoken") { - // We don't currently support silent discovery for credentials on USB tokens. - return Ok(thin_vec![]); - } else if static_prefs::pref!("security.webauth.webauthn_enable_softtoken") { - return self - .test_token_manager - .get_autofill_entries(&info.relying_party_id, &info.allow_list); - } else { - return Err(NS_ERROR_FAILURE); - } - } - - xpcom_method!(select_autofill_entry => SelectAutoFillEntry(aTid: u64, aCredentialId: *const ThinVec)); - fn select_autofill_entry(&self, tid: u64, credential_id: &ThinVec) -> Result<(), nsresult> { - let mut guard = self.transaction.lock().unwrap(); - let Some(state) = guard.as_mut() else { - return Err(NS_ERROR_FAILURE); - }; - if tid != state.tid { - return Err(NS_ERROR_FAILURE); - } - self.do_get_assertion(Some(credential_id.to_vec()), guard) - } - - xpcom_method!(resume_conditional_get => ResumeConditionalGet(aTid: u64)); - fn resume_conditional_get(&self, tid: u64) -> Result<(), nsresult> { - let mut guard = self.transaction.lock().unwrap(); - let Some(state) = guard.as_mut() else { - return Err(NS_ERROR_FAILURE); - }; - if tid != state.tid { - return Err(NS_ERROR_FAILURE); - } - self.do_get_assertion(None, guard) - } - xpcom_method!(cancel => Cancel(aTransactionId: u64)); fn cancel(&self, tid: u64) -> Result<(), nsresult> { { @@ -1335,9 +1219,9 @@ impl AuthrsService { browsing_context_id: 0, pending_args: None, promise: TransactionPromise::Listen, + interactive_receiver: None, pin_receiver: None, selection_receiver: None, - interactive_receiver: None, puat_cache: None, }); } diff --git a/dom/webauthn/authrs_bridge/src/test_token.rs b/dom/webauthn/authrs_bridge/src/test_token.rs index afc2ddbc75e7..1f4cb14bfbac 100644 --- a/dom/webauthn/authrs_bridge/src/test_token.rs +++ b/dom/webauthn/authrs_bridge/src/test_token.rs @@ -33,7 +33,7 @@ use authenticator::{RegisterResult, SignResult, StatusUpdate}; use base64::Engine; use moz_task::RunnableBuilder; use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_OK}; -use nsstring::{nsACString, nsAString, nsCString, nsString}; +use nsstring::{nsACString, nsCString}; use rand::{thread_rng, RngCore}; use std::cell::{Ref, RefCell}; use std::collections::{hash_map::Entry, HashMap}; @@ -42,7 +42,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; use thin_vec::ThinVec; -use xpcom::interfaces::{nsICredentialParameters, nsIWebAuthnAutoFillEntry}; +use xpcom::interfaces::nsICredentialParameters; use xpcom::{xpcom_method, RefPtr}; // All TestTokens use this fixed, randomly generated, AAGUID @@ -128,8 +128,8 @@ impl TestToken { thread_rng().fill_bytes(&mut pin_token); Self { protocol: FidoProtocol::CTAP2, - transport, versions, + transport, has_resident_key, has_user_verification, is_user_consenting, @@ -671,34 +671,6 @@ impl CredentialParameters { } } -#[xpcom(implement(nsIWebAuthnAutoFillEntry), atomic)] -struct WebAuthnAutoFillEntry { - rp: String, - credential_id: Vec, -} - -impl WebAuthnAutoFillEntry { - xpcom_method!(get_provider => GetProvider() -> u8); - fn get_provider(&self) -> Result { - Ok(nsIWebAuthnAutoFillEntry::PROVIDER_TEST_TOKEN) - } - - xpcom_method!(get_user_name => GetUserName() -> nsAString); - fn get_user_name(&self) -> Result { - Ok(nsString::from("Test User")) - } - - xpcom_method!(get_rp_id => GetRpId() -> nsAString); - fn get_rp_id(&self) -> Result { - Ok(nsString::from(&self.rp)) - } - - xpcom_method!(get_credential_id => GetCredentialId() -> ThinVec); - fn get_credential_id(&self) -> Result, nsresult> { - Ok(self.credential_id.as_slice().into()) - } -} - #[derive(Default)] pub(crate) struct TestTokenManager { state: Arc>>, @@ -930,45 +902,4 @@ impl TestTokenManager { false } - - pub fn get_autofill_entries( - &self, - rp_id: &str, - credential_filter: &Vec, - ) -> Result>>, nsresult> { - let guard = self.state.lock().map_err(|_| NS_ERROR_FAILURE)?; - let mut entries = ThinVec::new(); - - for token in guard.values() { - let credentials = token.get_credentials(); - for credential in credentials.deref() { - // The relying party ID must match. - if !rp_id.eq(&credential.rp.id) { - continue; - } - // Only discoverable credentials are admissible. - if !credential.is_discoverable_credential { - continue; - } - // Only credentials listed in the credential filter (if it is - // non-empty) are admissible. - if credential_filter.len() > 0 - && credential_filter - .iter() - .find(|cred| cred.id == credential.id) - .is_none() - { - continue; - } - let entry = WebAuthnAutoFillEntry::allocate(InitWebAuthnAutoFillEntry { - rp: credential.rp.id.clone(), - credential_id: credential.id.clone(), - }) - .query_interface::() - .ok_or(NS_ERROR_FAILURE)?; - entries.push(Some(entry)); - } - } - Ok(entries) - } } diff --git a/dom/webauthn/moz.build b/dom/webauthn/moz.build index 5d84dc06e794..1f1e516d2d71 100644 --- a/dom/webauthn/moz.build +++ b/dom/webauthn/moz.build @@ -43,7 +43,6 @@ UNIFIED_SOURCES += [ "AuthenticatorResponse.cpp", "PublicKeyCredential.cpp", "WebAuthnArgs.cpp", - "WebAuthnAutoFillEntry.cpp", "WebAuthnManager.cpp", "WebAuthnManagerBase.cpp", "WebAuthnPromiseHolder.cpp", diff --git a/dom/webauthn/nsIWebAuthnArgs.idl b/dom/webauthn/nsIWebAuthnArgs.idl index 72999092faa7..bec8bbacacd6 100644 --- a/dom/webauthn/nsIWebAuthnArgs.idl +++ b/dom/webauthn/nsIWebAuthnArgs.idl @@ -93,6 +93,4 @@ interface nsIWebAuthnSignArgs : nsISupports { // Arguably we don't need to pass it through since WebAuthnController can // cancel transactions. readonly attribute unsigned long timeoutMS; - - readonly attribute bool conditionallyMediated; }; diff --git a/dom/webauthn/nsIWebAuthnService.idl b/dom/webauthn/nsIWebAuthnService.idl index 652550805748..15bd414bb5f6 100644 --- a/dom/webauthn/nsIWebAuthnService.idl +++ b/dom/webauthn/nsIWebAuthnService.idl @@ -18,20 +18,6 @@ interface nsICredentialParameters : nsISupports readonly attribute uint32_t signCount; }; -[scriptable, uuid(686d552e-a39d-4ba2-8127-faca54274039)] -interface nsIWebAuthnAutoFillEntry: nsISupports -{ - const octet PROVIDER_UNKNOWN = 0; - const octet PROVIDER_TEST_TOKEN = 1; - const octet PROVIDER_PLATFORM_WINDOWS = 2; - const octet PROVIDER_PLATFORM_MACOS = 3; - const octet PROVIDER_PLATFORM_ANDROID = 4; - - readonly attribute octet provider; - readonly attribute AString userName; - readonly attribute AString rpId; - readonly attribute Array credentialId; -}; [scriptable, uuid(e236a9b4-a26f-11ed-b6cc-07a9834e19b1)] interface nsIWebAuthnService : nsISupports @@ -61,27 +47,6 @@ interface nsIWebAuthnService : nsISupports // "cancel" button. void cancel(in uint64_t aTransactionId); - // `hasPendingConditionalGet` returns the transaction ID of a pending - // conditionally-mediated getAssertion promise. The browsing context and - // origin arguments must match those of the pending promise. If there is no - // pending getAssertion promise, or the browsing context and origin do not - // match, then `hasPendingConditionalGet` returns 0. - uint64_t hasPendingConditionalGet(in uint64_t aBrowsingContextId, in AString aOrigin); - - // If there is a pending conditionally-mediated getAssertion promise with - // transaction ID equal to `aTransactionId`, `getAutoFillEntries` returns - // an nsIWebAuthnAutoFillEntry for each silently discoverable credential - // that can be used to fullfill the request. - Array getAutoFillEntries(in uint64_t aTransactionId); - - // A pending conditionally-mediated getAssertion promise is resolved by - // calling `selectAutoFillEntry` or `resumeConditionalGet`. - // `selectAutoFillEntry` specifies the credential ID that should be used to - // fulfill the request, whereas `resumeConditionalGet` indicates that any - // allowed credential can be used. - void selectAutoFillEntry(in uint64_t aTransactionId, in Array aCredentialId); - void resumeConditionalGet(in uint64_t aTransactionId); - void pinCallback(in uint64_t aTransactionId, in ACString aPin); void resumeMakeCredential(in uint64_t aTransactionId, in bool aForceNoneAttestation); void selectionCallback(in uint64_t aTransactionId, in uint64_t aIndex); diff --git a/dom/webauthn/tests/browser/browser.toml b/dom/webauthn/tests/browser/browser.toml index b08cf3d2564d..133dce859e89 100644 --- a/dom/webauthn/tests/browser/browser.toml +++ b/dom/webauthn/tests/browser/browser.toml @@ -11,7 +11,6 @@ prefs = [ "security.webauth.webauthn_enable_softtoken=true", "security.webauth.webauthn_enable_usbtoken=false", "security.webauthn.ctap2=true", - "security.webauthn.enable_conditional_mediation=true", ] ["browser_abort_visibility.js"] @@ -26,8 +25,6 @@ skip-if = [ "win11_2009", # Test not relevant on 1903+ ] -["browser_webauthn_conditional_mediation.js"] - ["browser_webauthn_ipaddress.js"] ["browser_webauthn_prompts.js"] diff --git a/dom/webauthn/tests/browser/browser_webauthn_conditional_mediation.js b/dom/webauthn/tests/browser/browser_webauthn_conditional_mediation.js deleted file mode 100644 index 755e5e06c548..000000000000 --- a/dom/webauthn/tests/browser/browser_webauthn_conditional_mediation.js +++ /dev/null @@ -1,124 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const TEST_URL = "https://example.com"; - -let gAuthenticatorId = add_virtual_authenticator(); -let gExpectNotAllowedError = expectError("NotAllowed"); -let gPendingConditionalGetSubject = "webauthn:conditional-get-pending"; -let gWebAuthnService = Cc["@mozilla.org/webauthn/service;1"].getService( - Ci.nsIWebAuthnService -); - -add_task(async function test_webauthn_resume_conditional_get() { - // Open a new tab. - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - - // TODO: Is there a better way to get the browsing context id? - let browser = tab.linkedBrowser.browsingContext.embedderElement; - let browsingContextId = browser.browsingContext.id; - - let transactionId = gWebAuthnService.hasPendingConditionalGet( - browsingContextId, - TEST_URL - ); - ok(transactionId == 0, "should not have a pending conditional get"); - - let requestStarted = TestUtils.topicObserved(gPendingConditionalGetSubject); - - let active = true; - let promise = promiseWebAuthnGetAssertionDiscoverable(tab, "conditional") - .then(arrivingHereIsBad) - .catch(gExpectNotAllowedError) - .then(() => (active = false)); - - await requestStarted; - - transactionId = gWebAuthnService.hasPendingConditionalGet(0, TEST_URL); - ok( - transactionId == 0, - "hasPendingConditionalGet should check the browsing context id" - ); - - transactionId = gWebAuthnService.hasPendingConditionalGet( - browsingContextId, - "https://example.org" - ); - ok(transactionId == 0, "hasPendingConditionalGet should check the origin"); - - transactionId = gWebAuthnService.hasPendingConditionalGet( - browsingContextId, - TEST_URL - ); - ok(transactionId != 0, "should have a pending conditional get"); - - ok(active, "request should still be active"); - - gWebAuthnService.resumeConditionalGet(transactionId); - await promise; - - ok(!active, "request should not be active"); - - // Close tab. - await BrowserTestUtils.removeTab(tab); -}); - -add_task(async function test_webauthn_select_autofill_entry() { - // Open a new tab. - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - - // Add credentials - let cred1 = await addCredential(gAuthenticatorId, "example.com"); - let cred2 = await addCredential(gAuthenticatorId, "example.com"); - - // TODO: Is there a better way to get the browsing context id? - let browser = tab.linkedBrowser.browsingContext.embedderElement; - let browsingContextId = browser.browsingContext.id; - - let transactionId = gWebAuthnService.hasPendingConditionalGet( - browsingContextId, - TEST_URL - ); - ok(transactionId == 0, "should not have a pending conditional get"); - - let requestStarted = TestUtils.topicObserved(gPendingConditionalGetSubject); - - let active = true; - let promise = promiseWebAuthnGetAssertionDiscoverable(tab, "conditional") - .catch(arrivingHereIsBad) - .then(() => (active = false)); - - await requestStarted; - - transactionId = gWebAuthnService.hasPendingConditionalGet( - browsingContextId, - TEST_URL - ); - ok(transactionId != 0, "should have a pending conditional get"); - - let autoFillEntries = gWebAuthnService.getAutoFillEntries(transactionId); - ok( - autoFillEntries.length == 2 && - autoFillEntries[0].rpId == "example.com" && - autoFillEntries[1].rpId == "example.com", - "should have two autofill entries for example.com" - ); - - gWebAuthnService.selectAutoFillEntry( - transactionId, - autoFillEntries[0].credentialId - ); - let result = await promise; - - ok(!active, "request should not be active"); - - // Remove credentials - gWebAuthnService.removeCredential(gAuthenticatorId, cred1); - gWebAuthnService.removeCredential(gAuthenticatorId, cred2); - - // Close tab. - await BrowserTestUtils.removeTab(tab); -}); diff --git a/dom/webauthn/tests/browser/head.js b/dom/webauthn/tests/browser/head.js index c6f6714e3f12..79a2e081f4ce 100644 --- a/dom/webauthn/tests/browser/head.js +++ b/dom/webauthn/tests/browser/head.js @@ -206,27 +206,19 @@ function promiseWebAuthnGetAssertion(tab, key_handle = null, extensions = {}) { ); } -function promiseWebAuthnGetAssertionDiscoverable( - tab, - mediation = "optional", - extensions = {} -) { - return ContentTask.spawn( - tab.linkedBrowser, - [extensions, mediation], - ([extensions, mediation]) => { - let challenge = content.crypto.getRandomValues(new Uint8Array(16)); +function promiseWebAuthnGetAssertionDiscoverable(tab, extensions = {}) { + return ContentTask.spawn(tab.linkedBrowser, [extensions], ([extensions]) => { + let challenge = content.crypto.getRandomValues(new Uint8Array(16)); - let publicKey = { - challenge, - extensions, - rpId: content.document.domain, - allowCredentials: [], - }; + let publicKey = { + challenge, + extensions, + rpId: content.document.domain, + allowCredentials: [], + }; - return content.navigator.credentials.get({ publicKey, mediation }); - } - ); + return content.navigator.credentials.get({ publicKey }); + }); } function checkRpIdHash(rpIdHash, hostname) { diff --git a/dom/webauthn/tests/mochitest.toml b/dom/webauthn/tests/mochitest.toml index 89e607950652..a19e53e7af26 100644 --- a/dom/webauthn/tests/mochitest.toml +++ b/dom/webauthn/tests/mochitest.toml @@ -13,7 +13,6 @@ prefs = [ "security.webauth.webauthn_enable_softtoken=true", "security.webauth.webauthn_enable_usbtoken=false", "security.webauthn.ctap2=true", - "security.webauthn.enable_conditional_mediation=true", ] ["test_webauthn_abort_signal.html"] diff --git a/dom/webidl/AutocompleteInfo.webidl b/dom/webidl/AutocompleteInfo.webidl index c75f6e4b8cfa..ebf2a3292c3c 100644 --- a/dom/webidl/AutocompleteInfo.webidl +++ b/dom/webidl/AutocompleteInfo.webidl @@ -14,6 +14,5 @@ dictionary AutocompleteInfo { DOMString addressType = ""; DOMString contactType = ""; DOMString fieldName = ""; - DOMString credentialType = ""; boolean canAutomaticallyPersist = true; }; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index db41a42e9c6a..bb1cc6d50226 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -13812,16 +13812,6 @@ value: true mirror: always -# WebAuthn conditional mediation -- name: security.webauthn.enable_conditional_mediation - type: RelaxedAtomicBool -#if defined(XP_MACOSX) - value: false -#else - value: @IS_EARLY_BETA_OR_EARLIER@ -#endif - mirror: always - # Dispatch WebAuthn requests to virtual authenticators (mutually exclusive # with and webauthn_enable_usbtoken) - name: security.webauth.webauthn_enable_softtoken diff --git a/testing/profiles/web-platform/user.js b/testing/profiles/web-platform/user.js index 70d465e85686..e99c1ab1c860 100644 --- a/testing/profiles/web-platform/user.js +++ b/testing/profiles/web-platform/user.js @@ -92,7 +92,5 @@ user_pref("security.webauth.webauthn_enable_softtoken", true); user_pref("security.webauth.webauthn_enable_usbtoken", false); // Disable the WebAuthn direct attestation consent prompt. user_pref("security.webauth.webauthn_testing_allow_direct_attestation", true); -// Enable WebAuthn conditional mediation. -user_pref("security.webauthn.enable_conditional_mediation", true); // Disable captive portal service user_pref("network.captive-portal-service.enabled", false); diff --git a/testing/web-platform/meta/html/semantics/forms/the-form-element/form-autocomplete.html.ini b/testing/web-platform/meta/html/semantics/forms/the-form-element/form-autocomplete.html.ini index 820153d5685d..f7bd789b2305 100644 --- a/testing/web-platform/meta/html/semantics/forms/the-form-element/form-autocomplete.html.ini +++ b/testing/web-platform/meta/html/semantics/forms/the-form-element/form-autocomplete.html.ini @@ -77,3 +77,9 @@ [one-time-code is an allowed autocomplete field name] expected: FAIL + + [webauthn is an allowed autocomplete field name] + expected: FAIL + + [Serialize combinations of section, mode, contact, field, and credential] + expected: FAIL diff --git a/testing/web-platform/meta/webauthn/conditional-mediation.https.html.ini b/testing/web-platform/meta/webauthn/conditional-mediation.https.html.ini index 48e6758ca196..7fcd8e830995 100644 --- a/testing/web-platform/meta/webauthn/conditional-mediation.https.html.ini +++ b/testing/web-platform/meta/webauthn/conditional-mediation.https.html.ini @@ -1,9 +1,3 @@ [conditional-mediation.https.html] [Conditional mediation supported] - expected: - if os == "android": FAIL - PASS - [Conditional mediation not supported] - expected: - if os == "android": PASS - FAIL + expected: FAIL diff --git a/toolkit/components/formautofill/shared/FieldScanner.sys.mjs b/toolkit/components/formautofill/shared/FieldScanner.sys.mjs index 22adfdabe818..8f95d3949e9e 100644 --- a/toolkit/components/formautofill/shared/FieldScanner.sys.mjs +++ b/toolkit/components/formautofill/shared/FieldScanner.sys.mjs @@ -32,7 +32,6 @@ export class FieldDetail { section = ""; addressType = ""; contactType = ""; - credentialType = ""; // When a field is split into N fields, we use part to record which field it is // For example, a credit card number field is split into 4 fields, the value of @@ -57,7 +56,6 @@ export class FieldDetail { this.section = autocompleteInfo.section; this.addressType = autocompleteInfo.addressType; this.contactType = autocompleteInfo.contactType; - this.credentialType = autocompleteInfo.credentialType; } else if (confidence) { this.reason = "fathom"; this.confidence = confidence; diff --git a/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs b/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs index 6ff96d999e5f..8951e17cb75d 100644 --- a/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs +++ b/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs @@ -673,7 +673,6 @@ export class LoginAutoComplete { isProbablyANewPasswordField, scenarioName: scenario?.constructor.name, inputMaxLength: inputElement.maxLength, - isWebAuthn: this.#isWebAuthnCredentials(autocompleteInfo), } ); @@ -704,15 +703,6 @@ export class LoginAutoComplete { this.#cachedNewPasswordScore.set(inputElement, score); return score >= threshold; } - - /** - * @param {string} autocompleteInfo - * @returns whether the non-autofill credential type (https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#non-autofill-credential-type) - * of the input field is "webauthn" - */ - #isWebAuthnCredentials(autocompleteInfo) { - return autocompleteInfo.credentialType == "webauthn"; - } } let gAutoCompleteListener = { diff --git a/toolkit/components/passwordmgr/LoginManagerParent.sys.mjs b/toolkit/components/passwordmgr/LoginManagerParent.sys.mjs index 862ab6b846d4..71a477adbd26 100644 --- a/toolkit/components/passwordmgr/LoginManagerParent.sys.mjs +++ b/toolkit/components/passwordmgr/LoginManagerParent.sys.mjs @@ -33,7 +33,6 @@ ChromeUtils.defineESModuleGetters(lazy, { LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs", MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs", NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", - WebAuthnFeature: "resource://gre/modules/WebAuthnFeature.sys.mjs", PasswordGenerator: "resource://gre/modules/PasswordGenerator.sys.mjs", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", }); @@ -385,10 +384,6 @@ export class LoginManagerParent extends JSWindowActorParent { ); return this.#generateRelayUsername(context.origin); } - - case "PasswordManager:promptForAuthenticator": { - return this.#promptForAuthenticator(data.selection); - } } return undefined; @@ -527,11 +522,6 @@ export class LoginManagerParent extends JSWindowActorParent { return lazy.FirefoxRelay.generateUsername(browser, origin); } - async #promptForAuthenticator(selection) { - const browser = lazy.LoginHelper.getBrowserForPrompt(this.getRootBrowser()); - return lazy.WebAuthnFeature.promptForAuthenticator(browser, selection); - } - /** * Update the remaining number of import suggestion impressions with debounce * to allow multiple popups showing the "same" items to count as one. @@ -720,7 +710,6 @@ export class LoginManagerParent extends JSWindowActorParent { isProbablyANewPasswordField, scenarioName, inputMaxLength, - isWebAuthn, } ) { // Note: previousResult is a regular object, not an @@ -818,31 +807,16 @@ export class LoginManagerParent extends JSWindowActorParent { // doesn't support structured cloning. let jsLogins = lazy.LoginHelper.loginsToVanillaObjects(matchingLogins); - let autocompleteItems = []; - - if (!hasBeenTypePassword) { - autocompleteItems.push( - ...(await lazy.FirefoxRelay.autocompleteItemsAsync({ - formOrigin, - scenarioName, - hasInput: !!searchStringLower.length, - })) - ); - } - autocompleteItems.push( - ...(await lazy.WebAuthnFeature.autocompleteItemsAsync( - this._overrideBrowsingContextId ?? - this.getRootBrowser().browsingContext.id, - formOrigin, - scenarioName, - isWebAuthn - )) - ); - return { generatedPassword, importable: await getImportableLogins(formOrigin), - autocompleteItems, + autocompleteItems: hasBeenTypePassword + ? [] + : await lazy.FirefoxRelay.autocompleteItemsAsync({ + formOrigin, + scenarioName, + hasInput: !!searchStringLower.length, + }), logins: jsLogins, willAutoSaveGeneratedPassword, }; diff --git a/toolkit/components/satchel/integrations/WebAuthnFeature.sys.mjs b/toolkit/components/satchel/integrations/WebAuthnFeature.sys.mjs deleted file mode 100644 index a2480e5ff4a3..000000000000 --- a/toolkit/components/satchel/integrations/WebAuthnFeature.sys.mjs +++ /dev/null @@ -1,129 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { - LoginHelper, - ParentAutocompleteOption, -} from "resource://gre/modules/LoginHelper.sys.mjs"; - -import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; - -const lazy = {}; - -XPCOMUtils.defineLazyServiceGetter( - lazy, - "webauthnService", - "@mozilla.org/webauthn/service;1", - "nsIWebAuthnService" -); - -ChromeUtils.defineLazyGetter( - lazy, - "strings", - () => new Localization(["browser/webauthnDialog.ftl"]) -); -ChromeUtils.defineLazyGetter(lazy, "log", () => - LoginHelper.createLogger("WebAuthnFeature") -); - -if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) { - throw new Error( - "PasskeySupport.sys.mjs should only run in the parent process" - ); -} - -class WebAuthnSupport { - async *#getAutocompleteItemsAsync(browsingContextId, formOrigin) { - let transactionId = lazy.webauthnService.hasPendingConditionalGet( - browsingContextId, - formOrigin - ); - if (transactionId == 0) { - // No pending transaction - return; - } - let credentials = lazy.webauthnService.getAutoFillEntries(transactionId); - - let labels = credentials.map(x => ({ - id: "webauthn-specific-passkey-label", - args: { domain: x.rpId }, - })); - if (!credentials.length) { - labels.push({ id: "webauthn-a-passkey-label" }); - } else { - labels.push({ id: "webauthn-another-passkey-label" }); - } - const formattedLabels = await lazy.strings.formatValues(labels); - for (let i = 0; i < credentials.length; i++) { - yield new ParentAutocompleteOption( - "chrome://browser/content/logos/etp-mobile.svg", // Bug 1867622: replace this with final icon - credentials[i].userName, - formattedLabels[i], - "PasswordManager:promptForAuthenticator", - { - selection: { - transactionId, - credentialId: credentials[i].credentialId, - }, - } - ); - } - // `getAutoFillEntries` may not return all of the credentials on the device - // (in particular it will not include credentials with a protection policy - // that forbids silent discovery), so we include a catch-all entry in the - // list. If the user selects this entry, the WebAuthn transaction will - // proceed using the modal UI. - yield new ParentAutocompleteOption( - "chrome://browser/content/logos/etp-mobile.svg", // Bug 1867622: replace this with final icon - formattedLabels[formattedLabels.length - 1], - "", - "PasswordManager:promptForAuthenticator", - { - selection: { - transactionId, - }, - } - ); - } - - /** - * - * @param {int} browsingContextId the browsing context ID associated with this request - * @param {string} formOrigin - * @param {string} scenarioName can be "SignUpFormScenario" or undefined - * @param {string} isWebAuthn indicates whether "webauthn" was included in the input's autocomplete value - * @returns {ParentAutocompleteOption} the optional WebAuthn autocomplete item - */ - async autocompleteItemsAsync( - browsingContextId, - formOrigin, - scenarioName, - isWebAuthn - ) { - const result = []; - if (scenarioName !== "SignUpFormScenario" || isWebAuthn) { - for await (const item of this.#getAutocompleteItemsAsync( - browsingContextId, - formOrigin - )) { - result.push(item); - } - } - return result; - } - - async promptForAuthenticator(browser, selection) { - lazy.log.info("Prompting to authenticate with relying party."); - if (selection.credentialId) { - lazy.webauthnService.selectAutoFillEntry( - selection.transactionId, - selection.credentialId - ); - } else { - lazy.webauthnService.resumeConditionalGet(selection.transactionId); - } - } -} - -export const WebAuthnFeature = new WebAuthnSupport(); diff --git a/toolkit/components/satchel/moz.build b/toolkit/components/satchel/moz.build index 90dbd9ad2d82..1bade891387f 100644 --- a/toolkit/components/satchel/moz.build +++ b/toolkit/components/satchel/moz.build @@ -35,7 +35,6 @@ EXTRA_JS_MODULES += [ "integrations/FirefoxRelay.sys.mjs", "integrations/FirefoxRelayTelemetry.mjs", "integrations/FirefoxRelayUtils.sys.mjs", - "integrations/WebAuthnFeature.sys.mjs", "SignUpFormRuleset.sys.mjs", ]