mirror of
https://github.com/bitwarden/browser.git
synced 2024-10-01 04:37:40 +02:00
[PM-6501] Search field disqualifications preventing filling password input fields (#8117)
* [PM-6501] Search field disqualifications preventing filling password input fields * [PM-6501] Reworking implementation of AutofillService.isSearchField to more carefully test search field attribute keywords * [PM-6501] Reworking implementation of AutofillService.isSearchField to more carefully test search field attribute keywords * [PM-6501] Reworking implementation of AutofillService.isSearchField to more carefully test search field attribute keywords
This commit is contained in:
parent
ebf51ebaaf
commit
10d503c15f
@ -3380,6 +3380,34 @@ describe("AutofillService", () => {
|
|||||||
|
|
||||||
expect(value).toBe(false);
|
expect(value).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("validates attribute identifiers with mixed camel case and non-alpha characters", () => {
|
||||||
|
const attributes: Record<string, boolean> = {
|
||||||
|
_$1_go_look: true,
|
||||||
|
go_look: true,
|
||||||
|
goLook: true,
|
||||||
|
go1look: true,
|
||||||
|
"go look": true,
|
||||||
|
look_go: true,
|
||||||
|
findPerson: true,
|
||||||
|
query$1: true,
|
||||||
|
look_goo: false,
|
||||||
|
golook: false,
|
||||||
|
lookgo: false,
|
||||||
|
logonField: false,
|
||||||
|
ego_input: false,
|
||||||
|
"Gold Password": false,
|
||||||
|
searching_for: false,
|
||||||
|
person_finder: false,
|
||||||
|
};
|
||||||
|
const autofillFieldMocks = Object.keys(attributes).map((key) =>
|
||||||
|
createAutofillFieldMock({ htmlID: key }),
|
||||||
|
);
|
||||||
|
autofillFieldMocks.forEach((field) => {
|
||||||
|
const value = AutofillService["isSearchField"](field);
|
||||||
|
expect(value).toBe(attributes[field.htmlID]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("isFieldMatch", () => {
|
describe("isFieldMatch", () => {
|
||||||
|
@ -44,6 +44,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
private openPasswordRepromptPopoutDebounce: NodeJS.Timeout;
|
private openPasswordRepromptPopoutDebounce: NodeJS.Timeout;
|
||||||
private currentlyOpeningPasswordRepromptPopout = false;
|
private currentlyOpeningPasswordRepromptPopout = false;
|
||||||
private autofillScriptPortsSet = new Set<chrome.runtime.Port>();
|
private autofillScriptPortsSet = new Set<chrome.runtime.Port>();
|
||||||
|
static searchFieldNamesSet = new Set(AutoFillConstants.SearchFieldNames);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
@ -1380,11 +1381,33 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return excludedTypes.indexOf(type) > -1;
|
return excludedTypes.indexOf(type) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies if a passed field contains text artifacts that identify it as a search field.
|
||||||
|
*
|
||||||
|
* @param field - The autofill field that we are validating as a search field
|
||||||
|
*/
|
||||||
private static isSearchField(field: AutofillField) {
|
private static isSearchField(field: AutofillField) {
|
||||||
const matchFieldAttributeValues = [field.type, field.htmlName, field.htmlID, field.placeholder];
|
const matchFieldAttributeValues = [field.type, field.htmlName, field.htmlID, field.placeholder];
|
||||||
const matchPattern = new RegExp(AutoFillConstants.SearchFieldNames.join("|"), "gi");
|
for (let attrIndex = 0; attrIndex < matchFieldAttributeValues.length; attrIndex++) {
|
||||||
|
if (!matchFieldAttributeValues[attrIndex]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
return Boolean(matchFieldAttributeValues.join(" ").match(matchPattern));
|
// Separate camel case words and case them to lower case values
|
||||||
|
const camelCaseSeparatedFieldAttribute = matchFieldAttributeValues[attrIndex]
|
||||||
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
||||||
|
.toLowerCase();
|
||||||
|
// Split the attribute by non-alphabetical characters to get the keywords
|
||||||
|
const attributeKeywords = camelCaseSeparatedFieldAttribute.split(/[^a-z]/gi);
|
||||||
|
|
||||||
|
for (let keywordIndex = 0; keywordIndex < attributeKeywords.length; keywordIndex++) {
|
||||||
|
if (AutofillService.searchFieldNamesSet.has(attributeKeywords[keywordIndex])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static isExcludedFieldType(field: AutofillField, excludedTypes: string[]) {
|
static isExcludedFieldType(field: AutofillField, excludedTypes: string[]) {
|
||||||
@ -1397,11 +1420,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the input is an untyped/mistyped search input
|
// Check if the input is an untyped/mistyped search input
|
||||||
if (this.isSearchField(field)) {
|
return this.isSearchField(field);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1525,11 +1544,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AutoFillConstants.PasswordFieldExcludeList.some((i) => cleanedValue.indexOf(i) > -1)) {
|
return !AutoFillConstants.PasswordFieldExcludeList.some((i) => cleanedValue.indexOf(i) > -1);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fieldHasDisqualifyingAttributeValue(field: AutofillField) {
|
static fieldHasDisqualifyingAttributeValue(field: AutofillField) {
|
||||||
@ -1572,7 +1587,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
const arr: AutofillField[] = [];
|
const arr: AutofillField[] = [];
|
||||||
|
|
||||||
pageDetails.fields.forEach((f) => {
|
pageDetails.fields.forEach((f) => {
|
||||||
if (AutofillService.isExcludedFieldType(f, AutoFillConstants.ExcludedAutofillLoginTypes)) {
|
const isPassword = f.type === "password";
|
||||||
|
if (
|
||||||
|
!isPassword &&
|
||||||
|
AutofillService.isExcludedFieldType(f, AutoFillConstants.ExcludedAutofillLoginTypes)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1581,23 +1600,16 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPassword = f.type === "password";
|
|
||||||
|
|
||||||
const isLikePassword = () => {
|
const isLikePassword = () => {
|
||||||
if (f.type !== "text") {
|
if (f.type !== "text") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AutofillService.valueIsLikePassword(f.htmlID)) {
|
const testedValues = [f.htmlID, f.htmlName, f.placeholder];
|
||||||
|
for (let i = 0; i < testedValues.length; i++) {
|
||||||
|
if (AutofillService.valueIsLikePassword(testedValues[i])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AutofillService.valueIsLikePassword(f.htmlName)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AutofillService.valueIsLikePassword(f.placeholder)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user