diff --git a/apps/browser/src/autofill/services/autofill-constants.ts b/apps/browser/src/autofill/services/autofill-constants.ts index 7467d5d4ba7..92c9a508333 100644 --- a/apps/browser/src/autofill/services/autofill-constants.ts +++ b/apps/browser/src/autofill/services/autofill-constants.ts @@ -46,6 +46,8 @@ export class AutoFillConstants { "verification code", ]; + static readonly RecoveryCodeFieldNames: string[] = ["backup", "recovery"]; + static readonly AmbiguousTotpFieldNames: string[] = ["code", "pin", "otc", "otp", "2fa", "mfa"]; static readonly SearchFieldNames: string[] = ["search", "query", "find", "go"]; diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts index f9430387c83..663ae2ea569 100644 --- a/apps/browser/src/autofill/services/autofill.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill.service.spec.ts @@ -4487,6 +4487,34 @@ describe("AutofillService", () => { expect(result).toBe(totpField); }); + + it("returns null if the totp field matches excluded TOTP field names via htmlID", () => { + totpField.htmlID = "recovery-code"; + + const result = autofillService["findTotpField"]( + pageDetails, + passwordField, + false, + false, + false, + ); + + expect(result).toBeNull(); + }); + + it("returns null if the totp field matches excluded TOTP field names via htmlName", () => { + totpField.htmlName = "backup"; + + const result = autofillService["findTotpField"]( + pageDetails, + passwordField, + false, + false, + false, + ); + + expect(result).toBeNull(); + }); }); describe("findMatchingFieldIndex", () => { diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index 51c0dd3f247..2b15d8fd587 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -948,7 +948,8 @@ export default class AutofillService implements AutofillServiceInterface { ...AutoFillConstants.TotpFieldNames, ...AutoFillConstants.AmbiguousTotpFieldNames, ]) || - field.autoCompleteType === "one-time-code"); + field.autoCompleteType === "one-time-code") && + !AutofillService.fieldIsFuzzyMatch(field, [...AutoFillConstants.RecoveryCodeFieldNames]); const isFillableUsernameField = !options.skipUsernameOnlyFill && @@ -2357,11 +2358,15 @@ export default class AutofillService implements AutofillServiceInterface { (canBeReadOnly || !f.readonly) && (withoutForm || f.form === passwordField.form) && (canBeHidden || f.viewable) && - (f.type === "text" || f.type === "number") && + (f.type === "text" || + f.type === "number" || + // sites will commonly use tel in order to get the digit pad against semantic recommendations + f.type === "tel") && AutofillService.fieldIsFuzzyMatch(f, [ ...AutoFillConstants.TotpFieldNames, ...AutoFillConstants.AmbiguousTotpFieldNames, - ]) + ]) && + !AutofillService.fieldIsFuzzyMatch(f, [...AutoFillConstants.RecoveryCodeFieldNames]) ) { totpField = f; @@ -2551,7 +2556,7 @@ export default class AutofillService implements AutofillServiceInterface { if (!AutofillService.hasValue(value)) { continue; } - if (this.fuzzyMatch(names, value)) { + if (AutofillService.fuzzyMatch(names, value)) { return showMatch ? [true, { attr, value }] : true; } } @@ -2567,7 +2572,13 @@ export default class AutofillService implements AutofillServiceInterface { * @private */ private static fuzzyMatch(options: string[], value: string): boolean { - if (options == null || options.length === 0 || value == null || value === "") { + if ( + options == null || + options.length === 0 || + value == null || + typeof value !== "string" || + value.length < 1 + ) { return false; } diff --git a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts index b12017484eb..497c8ce2b35 100644 --- a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts +++ b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts @@ -16,6 +16,7 @@ import { SubmitChangePasswordButtonNames, SubmitLoginButtonNames, } from "./autofill-constants"; +import AutofillService from "./autofill.service"; export class InlineMenuFieldQualificationService implements InlineMenuFieldQualificationServiceInterface @@ -1071,6 +1072,10 @@ export class InlineMenuFieldQualificationService * @param field - The field to validate */ isTotpField = (field: AutofillField): boolean => { + if (AutofillService.fieldIsFuzzyMatch(field, [...AutoFillConstants.RecoveryCodeFieldNames])) { + return false; + } + if (this.fieldContainsAutocompleteValues(field, this.totpFieldAutocompleteValue)) { return true; }