mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
fix: [PM-23494] detect ID vs login inputs on booksamillion.com (#15548)
* fix: [PM-23494] add newsletter checks; cleanup Signed-off-by: Ben Brooks <bbrooks@bitwarden.com> * fix: [PM-23494] improve isExplicitIdentityEmailField, add NewEmailFieldKeywords Signed-off-by: Ben Brooks <bbrooks@bitwarden.com> * fix: [PM-23494] improve isNewsletterForm, add NewsletterFormNames Signed-off-by: Ben Brooks <bbrooks@bitwarden.com> --------- Signed-off-by: Ben Brooks <bbrooks@bitwarden.com>
This commit is contained in:
@@ -50,6 +50,15 @@ export class AutoFillConstants {
|
||||
|
||||
static readonly SearchFieldNames: string[] = ["search", "query", "find", "go"];
|
||||
|
||||
static readonly NewEmailFieldKeywords: string[] = [
|
||||
"new-email",
|
||||
"newemail",
|
||||
"new email",
|
||||
"neue e-mail",
|
||||
];
|
||||
|
||||
static readonly NewsletterFormNames: string[] = ["newsletter"];
|
||||
|
||||
static readonly FieldIgnoreList: string[] = ["captcha", "findanything", "forgot"];
|
||||
|
||||
static readonly PasswordFieldExcludeList: string[] = [
|
||||
|
||||
@@ -58,6 +58,8 @@ export class InlineMenuFieldQualificationService
|
||||
"neue e-mail",
|
||||
"pwdcheck",
|
||||
];
|
||||
private newEmailFieldKeywords = new Set(AutoFillConstants.NewEmailFieldKeywords);
|
||||
private newsletterFormKeywords = new Set(AutoFillConstants.NewsletterFormNames);
|
||||
private updatePasswordFieldKeywords = [
|
||||
"update password",
|
||||
"change password",
|
||||
@@ -152,6 +154,61 @@ export class InlineMenuFieldQualificationService
|
||||
private totpFieldAutocompleteValue = "one-time-code";
|
||||
private premiumEnabled = false;
|
||||
|
||||
/**
|
||||
* Validates the provided field to indicate if the field is a new email field used for account creation/registration.
|
||||
*
|
||||
* @param field - The field to validate
|
||||
*/
|
||||
private isExplicitIdentityEmailField(field: AutofillField): boolean {
|
||||
const matchFieldAttributeValues = [field.type, field.htmlName, field.htmlID, field.placeholder];
|
||||
for (let attrIndex = 0; attrIndex < matchFieldAttributeValues.length; attrIndex++) {
|
||||
if (!matchFieldAttributeValues[attrIndex]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let keywordIndex = 0; keywordIndex < matchFieldAttributeValues.length; keywordIndex++) {
|
||||
if (this.newEmailFieldKeywords.has(matchFieldAttributeValues[attrIndex])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the provided form to indicate if the form is related to newsletter registration.
|
||||
*
|
||||
* @param parentForm - The form to validate
|
||||
*/
|
||||
private isNewsletterForm(parentForm: any): boolean {
|
||||
if (!parentForm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const matchFieldAttributeValues = [
|
||||
parentForm.type,
|
||||
parentForm.htmlName,
|
||||
parentForm.htmlID,
|
||||
parentForm.placeholder,
|
||||
];
|
||||
|
||||
for (let attrIndex = 0; attrIndex < matchFieldAttributeValues.length; attrIndex++) {
|
||||
const attrValue = matchFieldAttributeValues[attrIndex];
|
||||
if (!attrValue || typeof attrValue !== "string") {
|
||||
continue;
|
||||
}
|
||||
const attrValueLower = attrValue.toLowerCase();
|
||||
for (const keyword of this.newsletterFormKeywords) {
|
||||
if (attrValueLower.includes(keyword.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
void Promise.all([
|
||||
sendExtensionMessage("getInlineMenuFieldQualificationFeatureFlag"),
|
||||
@@ -300,7 +357,11 @@ export class InlineMenuFieldQualificationService
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.fieldContainsAutocompleteValues(field, this.identityAutocompleteValues);
|
||||
return (
|
||||
// Recognize explicit identity email fields (like id="new-email")
|
||||
this.isFieldForIdentityEmail(field) ||
|
||||
this.fieldContainsAutocompleteValues(field, this.identityAutocompleteValues)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,6 +458,12 @@ export class InlineMenuFieldQualificationService
|
||||
): boolean {
|
||||
// If the provided field is set with an autocomplete of "username", we should assume that
|
||||
// the page developer intends for this field to be interpreted as a username field.
|
||||
|
||||
// Exclude non-login email field from being treated as a login username field
|
||||
if (this.isExplicitIdentityEmailField(field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.fieldContainsAutocompleteValues(field, this.loginUsernameAutocompleteValues)) {
|
||||
const newPasswordFieldsInPageDetails = pageDetails.fields.filter(
|
||||
(field) => field.viewable && this.isNewPasswordField(field),
|
||||
@@ -415,6 +482,10 @@ export class InlineMenuFieldQualificationService
|
||||
const parentForm = pageDetails.forms[field.form];
|
||||
const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isCurrentPasswordField);
|
||||
|
||||
if (this.isNewsletterForm(parentForm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the field is not structured within a form, we need to identify if the field is used in conjunction
|
||||
// with a password field. If that's the case, then we should assume that it is a form field element.
|
||||
if (!parentForm) {
|
||||
@@ -822,9 +893,14 @@ export class InlineMenuFieldQualificationService
|
||||
* @param field - The field to validate
|
||||
*/
|
||||
isFieldForIdentityEmail = (field: AutofillField): boolean => {
|
||||
if (this.isExplicitIdentityEmailField(field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
this.fieldContainsAutocompleteValues(field, this.emailAutocompleteValue) ||
|
||||
field.type === "email"
|
||||
field.type === "email" ||
|
||||
field.htmlName === "email"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user