summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
commit59203c63bb777a3bacec32fb8830fba33540e809 (patch)
tree58298e711c0ff0575818c30485b44a2f21bf28a0 /toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs
parentAdding upstream version 126.0.1. (diff)
downloadfirefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz
firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs')
-rw-r--r--toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs254
1 files changed, 3 insertions, 251 deletions
diff --git a/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs b/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs
index 187caf9d62..a7ea1bfa2c 100644
--- a/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs
+++ b/toolkit/components/passwordmgr/LoginAutoComplete.sys.mjs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
- * nsIAutoCompleteResult and nsILoginAutoCompleteSearch implementations for saved logins.
+ * nsIAutoCompleteResult implementations for saved logins.
*/
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
@@ -15,11 +15,7 @@ import {
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
- InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.sys.mjs",
- LoginFormFactory: "resource://gre/modules/LoginFormFactory.sys.mjs",
LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
- LoginManagerChild: "resource://gre/modules/LoginManagerChild.sys.mjs",
- NewPasswordModel: "resource://gre/modules/NewPasswordModel.sys.mjs",
});
XPCOMUtils.defineLazyServiceGetter(
lazy,
@@ -335,6 +331,8 @@ export class LoginAutoCompleteResult {
// The footer comes last if it's enabled
if (isFooterEnabled()) {
+ // TODO: This would be removed once autofill is triggered from the parent.
+ gAutoCompleteListener.init();
if (autocompleteItems) {
this.#rows.push(
...autocompleteItems.map(
@@ -472,252 +470,6 @@ export class LoginAutoCompleteResult {
}
}
-export class LoginAutoComplete {
- // HTMLInputElement to number, the element's new-password heuristic confidence score
- #cachedNewPasswordScore = new WeakMap();
- #autoCompleteLookupPromise = null;
- classID = Components.ID("{2bdac17c-53f1-4896-a521-682ccdeef3a8}");
- QueryInterface = ChromeUtils.generateQI(["nsILoginAutoCompleteSearch"]);
-
- /**
- * Yuck. This is called directly by satchel:
- * nsFormFillController::StartSearch()
- * [toolkit/components/satchel/nsFormFillController.cpp]
- *
- * We really ought to have a simple way for code to register an
- * auto-complete provider, and not have satchel calling pwmgr directly.
- *
- * @param {string} aSearchString The value typed in the field.
- * @param {nsIAutoCompleteResult} aPreviousResult
- * @param {HTMLInputElement} aElement
- * @param {nsIFormFillCompleteObserver} aCallback
- */
- startSearch(aSearchString, aPreviousResult, aElement, aCallback) {
- let { isNullPrincipal } = aElement.nodePrincipal;
- if (
- aElement.nodePrincipal.schemeIs("about") ||
- aElement.nodePrincipal.isSystemPrincipal
- ) {
- // Don't show autocomplete results for about: pages.
- // XXX: Don't we need to call the callback here?
- return;
- }
-
- let searchStartTimeMS = Services.telemetry.msSystemNow();
-
- // Show the insecure login warning in the passwords field on null principal documents.
- // Avoid loading InsecurePasswordUtils.sys.mjs in a sandboxed document (e.g. an ad. frame) if we
- // already know it has a null principal and will therefore get the insecure autocomplete
- // treatment.
- // InsecurePasswordUtils doesn't handle the null principal case as not secure because we don't
- // want the same treatment:
- // * The web console warnings will be confusing (as they're primarily about http:) and not very
- // useful if the developer intentionally sandboxed the document.
- // * The site identity insecure field warning would require LoginManagerChild being loaded and
- // listening to some of the DOM events we're ignoring in null principal documents. For memory
- // reasons it's better to not load LMC at all for these sandboxed frames. Also, if the top-
- // document is sandboxing a document, it probably doesn't want that sandboxed document to be
- // able to affect the identity icon in the address bar by adding a password field.
- let form = lazy.LoginFormFactory.createFromField(aElement);
- let isSecure =
- !isNullPrincipal && lazy.InsecurePasswordUtils.isFormSecure(form);
- let { hasBeenTypePassword } = aElement;
- let hostname = aElement.ownerDocument.documentURIObject.host;
- let formOrigin = lazy.LoginHelper.getLoginOrigin(
- aElement.ownerDocument.documentURI
- );
- let loginManagerActor = lazy.LoginManagerChild.forWindow(
- aElement.ownerGlobal
- );
- let completeSearch = async autoCompleteLookupPromise => {
- // Assign to the member synchronously before awaiting the Promise.
- this.#autoCompleteLookupPromise = autoCompleteLookupPromise;
-
- let {
- generatedPassword,
- importable,
- logins,
- autocompleteItems,
- willAutoSaveGeneratedPassword,
- } = await autoCompleteLookupPromise;
-
- // If the search was canceled before we got our
- // results, don't bother reporting them.
- // N.B. This check must occur after the `await` above for it to be
- // effective.
- if (this.#autoCompleteLookupPromise !== autoCompleteLookupPromise) {
- lazy.log.debug("Ignoring result from previous search.");
- return;
- }
-
- let telemetryEventData = {
- acFieldName: aElement.getAutocompleteInfo().fieldName,
- hadPrevious: !!aPreviousResult,
- typeWasPassword: aElement.hasBeenTypePassword,
- fieldType: aElement.type,
- searchStartTimeMS,
- stringLength: aSearchString.length,
- };
-
- this.#autoCompleteLookupPromise = null;
- let results = new LoginAutoCompleteResult(
- aSearchString,
- logins,
- autocompleteItems,
- formOrigin,
- {
- generatedPassword,
- willAutoSaveGeneratedPassword,
- importable,
- actor: loginManagerActor,
- isSecure,
- hasBeenTypePassword,
- hostname,
- telemetryEventData,
- }
- );
- aCallback.onSearchCompletion(results);
- };
-
- if (isNullPrincipal) {
- // Don't search login storage when the field has a null principal as we don't want to fill
- // logins for the `location` in this case.
- completeSearch(Promise.resolve({ logins: [] }));
- return;
- }
-
- if (
- hasBeenTypePassword &&
- aSearchString &&
- !loginManagerActor.isPasswordGenerationForcedOn(aElement)
- ) {
- // Return empty result on password fields with password already filled,
- // unless password generation was forced.
- completeSearch(Promise.resolve({ logins: [] }));
- return;
- }
-
- if (!lazy.LoginHelper.enabled) {
- completeSearch(Promise.resolve({ logins: [] }));
- return;
- }
-
- let previousResult;
- if (aPreviousResult) {
- previousResult = {
- searchString: aPreviousResult.searchString,
- logins: lazy.LoginHelper.loginsToVanillaObjects(
- aPreviousResult.wrappedJSObject.logins
- ),
- };
- } else {
- previousResult = null;
- }
-
- let acLookupPromise = this.#requestAutoCompleteResultsFromParent({
- searchString: aSearchString,
- previousResult,
- inputElement: aElement,
- form,
- hasBeenTypePassword,
- });
- completeSearch(acLookupPromise).catch(lazy.log.error.bind(lazy.log));
- }
-
- stopSearch() {
- this.#autoCompleteLookupPromise = null;
- }
-
- async #requestAutoCompleteResultsFromParent({
- searchString,
- previousResult,
- inputElement,
- form,
- hasBeenTypePassword,
- }) {
- let actionOrigin = lazy.LoginHelper.getFormActionOrigin(form);
- let autocompleteInfo = inputElement.getAutocompleteInfo();
-
- let loginManagerActor = lazy.LoginManagerChild.forWindow(
- inputElement.ownerGlobal
- );
- let forcePasswordGeneration = false;
- let isProbablyANewPasswordField = false;
- if (hasBeenTypePassword) {
- forcePasswordGeneration =
- loginManagerActor.isPasswordGenerationForcedOn(inputElement);
- // Run the Fathom model only if the password field does not have the
- // autocomplete="new-password" attribute.
- isProbablyANewPasswordField =
- autocompleteInfo.fieldName == "new-password" ||
- this.isProbablyANewPasswordField(inputElement);
- }
- const scenario = loginManagerActor.getScenario(inputElement);
-
- if (lazy.LoginHelper.showAutoCompleteFooter) {
- gAutoCompleteListener.init();
- }
-
- lazy.log.debug("LoginAutoComplete search:", {
- forcePasswordGeneration,
- hasBeenTypePassword,
- isProbablyANewPasswordField,
- searchStringLength: searchString.length,
- });
-
- const result = await loginManagerActor.sendQuery(
- "PasswordManager:autoCompleteLogins",
- {
- actionOrigin,
- searchString,
- previousResult,
- forcePasswordGeneration,
- hasBeenTypePassword,
- isProbablyANewPasswordField,
- scenarioName: scenario?.constructor.name,
- inputMaxLength: inputElement.maxLength,
- isWebAuthn: this.#isWebAuthnCredentials(autocompleteInfo),
- }
- );
-
- return {
- generatedPassword: result.generatedPassword,
- importable: result.importable,
- autocompleteItems: result.autocompleteItems,
- logins: lazy.LoginHelper.vanillaObjectsToLogins(result.logins),
- willAutoSaveGeneratedPassword: result.willAutoSaveGeneratedPassword,
- };
- }
-
- isProbablyANewPasswordField(inputElement) {
- const threshold = lazy.LoginHelper.generationConfidenceThreshold;
- if (threshold == -1) {
- // Fathom is disabled
- return false;
- }
-
- let score = this.#cachedNewPasswordScore.get(inputElement);
- if (score) {
- return score >= threshold;
- }
-
- const { rules, type } = lazy.NewPasswordModel;
- const results = rules.against(inputElement);
- score = results.get(inputElement).scoreFor(type);
- 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 = {
added: false,