[PM-10420] Autofill focus jumps around after autofilling identity (#10361)
* [PM-10420] Autofill focus jumps around after autofilling identity ciphers * [PM-10420] Autofill focus jumps around after autofilling identity ciphers * [PM-10420] Autofill focus jumps around after autofilling identity ciphers * [PM-10420] Incorporating the feature flag within jest to test the validity of both implementations * [PM-10420] Refactoring how we compile the combined list of keywords * [PM-10420] Adding JSDocs to the implemented methods
This commit is contained in:
parent
c50a9063bc
commit
76351ce750
|
@ -76,6 +76,11 @@ export class AutoFillConstants {
|
|||
"textarea",
|
||||
...AutoFillConstants.ExcludedAutofillTypes,
|
||||
];
|
||||
|
||||
static readonly ExcludedIdentityAutocompleteTypes: Set<string> = new Set([
|
||||
"current-password",
|
||||
"new-password",
|
||||
]);
|
||||
}
|
||||
|
||||
export class CreditCardAutoFillConstants {
|
||||
|
|
|
@ -60,7 +60,7 @@ import {
|
|||
GenerateFillScriptOptions,
|
||||
PageDetail,
|
||||
} from "./abstractions/autofill.service";
|
||||
import { AutoFillConstants, IdentityAutoFillConstants } from "./autofill-constants";
|
||||
import { AutoFillConstants } from "./autofill-constants";
|
||||
import AutofillService from "./autofill.service";
|
||||
|
||||
const mockEquivalentDomains = [
|
||||
|
@ -3056,12 +3056,12 @@ describe("AutofillService", () => {
|
|||
options.cipher.identity = mock<IdentityView>();
|
||||
});
|
||||
|
||||
it("returns null if an identify is not found within the cipher", () => {
|
||||
it("returns null if an identify is not found within the cipher", async () => {
|
||||
options.cipher.identity = null;
|
||||
jest.spyOn(autofillService as any, "makeScriptAction");
|
||||
jest.spyOn(autofillService as any, "makeScriptActionWithValue");
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
|
@ -3087,432 +3087,389 @@ describe("AutofillService", () => {
|
|||
jest.spyOn(autofillService as any, "makeScriptActionWithValue");
|
||||
});
|
||||
|
||||
it("will not attempt to match custom fields", () => {
|
||||
const customField = createAutofillFieldMock({ tagName: "span" });
|
||||
pageDetails.fields.push(customField);
|
||||
let isRefactorFeatureFlagSet = false;
|
||||
for (let index = 0; index < 2; index++) {
|
||||
describe(`when the isRefactorFeatureFlagSet is ${isRefactorFeatureFlagSet}`, () => {
|
||||
beforeEach(() => {
|
||||
configService.getFeatureFlag.mockResolvedValue(isRefactorFeatureFlagSet);
|
||||
});
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
afterAll(() => {
|
||||
isRefactorFeatureFlagSet = true;
|
||||
});
|
||||
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(customField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled();
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
it("will not attempt to match custom fields", async () => {
|
||||
const customField = createAutofillFieldMock({ tagName: "span" });
|
||||
pageDetails.fields.push(customField);
|
||||
|
||||
it("will not attempt to match a field that is of an excluded type", () => {
|
||||
const excludedField = createAutofillFieldMock({ type: "hidden" });
|
||||
pageDetails.fields.push(excludedField);
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(customField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled();
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(excludedField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalledWith(
|
||||
excludedField,
|
||||
AutoFillConstants.ExcludedAutofillTypes,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
it("will not attempt to match a field that is of an excluded type", async () => {
|
||||
const excludedField = createAutofillFieldMock({ type: "hidden" });
|
||||
pageDetails.fields.push(excludedField);
|
||||
|
||||
it("will not attempt to match a field that is not viewable", () => {
|
||||
const viewableField = createAutofillFieldMock({ viewable: false });
|
||||
pageDetails.fields.push(viewableField);
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(excludedField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalledWith(
|
||||
excludedField,
|
||||
AutoFillConstants.ExcludedAutofillTypes,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(viewableField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled();
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
it("will not attempt to match a field that is not viewable", async () => {
|
||||
const viewableField = createAutofillFieldMock({ viewable: false });
|
||||
pageDetails.fields.push(viewableField);
|
||||
|
||||
it("will match a full name field to the vault item identity value", () => {
|
||||
const fullNameField = createAutofillFieldMock({ opid: "fullName", htmlName: "full-name" });
|
||||
pageDetails.fields = [fullNameField];
|
||||
options.cipher.identity.firstName = firstName;
|
||||
options.cipher.identity.middleName = middleName;
|
||||
options.cipher.identity.lastName = lastName;
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(viewableField);
|
||||
expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled();
|
||||
expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled();
|
||||
expect(value.script).toStrictEqual([]);
|
||||
});
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
fullNameField.htmlName,
|
||||
IdentityAutoFillConstants.FullNameFieldNames,
|
||||
IdentityAutoFillConstants.FullNameFieldNameValues,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
`${firstName} ${middleName} ${lastName}`,
|
||||
fullNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual([
|
||||
"fill_by_opid",
|
||||
fullNameField.opid,
|
||||
`${firstName} ${middleName} ${lastName}`,
|
||||
]);
|
||||
});
|
||||
it("will match a full name field to the vault item identity value", async () => {
|
||||
const fullNameField = createAutofillFieldMock({
|
||||
opid: "fullName",
|
||||
htmlName: "full-name",
|
||||
});
|
||||
pageDetails.fields = [fullNameField];
|
||||
options.cipher.identity.firstName = firstName;
|
||||
options.cipher.identity.middleName = middleName;
|
||||
options.cipher.identity.lastName = lastName;
|
||||
|
||||
it("will match a full name field to the a vault item that only has a last name", () => {
|
||||
const fullNameField = createAutofillFieldMock({ opid: "fullName", htmlName: "full-name" });
|
||||
pageDetails.fields = [fullNameField];
|
||||
options.cipher.identity.firstName = "";
|
||||
options.cipher.identity.middleName = "";
|
||||
options.cipher.identity.lastName = lastName;
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
`${firstName} ${middleName} ${lastName}`,
|
||||
fullNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual([
|
||||
"fill_by_opid",
|
||||
fullNameField.opid,
|
||||
`${firstName} ${middleName} ${lastName}`,
|
||||
]);
|
||||
});
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
fullNameField.htmlName,
|
||||
IdentityAutoFillConstants.FullNameFieldNames,
|
||||
IdentityAutoFillConstants.FullNameFieldNameValues,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
lastName,
|
||||
fullNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", fullNameField.opid, lastName]);
|
||||
});
|
||||
it("will match a full name field to the a vault item that only has a last name", async () => {
|
||||
const fullNameField = createAutofillFieldMock({
|
||||
opid: "fullName",
|
||||
htmlName: "full-name",
|
||||
});
|
||||
pageDetails.fields = [fullNameField];
|
||||
options.cipher.identity.firstName = "";
|
||||
options.cipher.identity.middleName = "";
|
||||
options.cipher.identity.lastName = lastName;
|
||||
|
||||
it("will match first name, middle name, and last name fields to the vault item identity value", () => {
|
||||
const firstNameField = createAutofillFieldMock({
|
||||
opid: "firstName",
|
||||
htmlName: "first-name",
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
lastName,
|
||||
fullNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", fullNameField.opid, lastName]);
|
||||
});
|
||||
|
||||
it("will match first name, middle name, and last name fields to the vault item identity value", async () => {
|
||||
const firstNameField = createAutofillFieldMock({
|
||||
opid: "firstName",
|
||||
htmlName: "first-name",
|
||||
});
|
||||
const middleNameField = createAutofillFieldMock({
|
||||
opid: "middleName",
|
||||
htmlName: "middle-name",
|
||||
});
|
||||
const lastNameField = createAutofillFieldMock({
|
||||
opid: "lastName",
|
||||
htmlName: "last-name",
|
||||
});
|
||||
pageDetails.fields = [firstNameField, middleNameField, lastNameField];
|
||||
options.cipher.identity.firstName = firstName;
|
||||
options.cipher.identity.middleName = middleName;
|
||||
options.cipher.identity.lastName = lastName;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity.firstName,
|
||||
firstNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity.middleName,
|
||||
middleNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity.lastName,
|
||||
lastNameField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", firstNameField.opid, firstName]);
|
||||
expect(value.script[5]).toStrictEqual([
|
||||
"fill_by_opid",
|
||||
middleNameField.opid,
|
||||
middleName,
|
||||
]);
|
||||
expect(value.script[8]).toStrictEqual(["fill_by_opid", lastNameField.opid, lastName]);
|
||||
});
|
||||
|
||||
it("will match title and email fields to the vault item identity value", async () => {
|
||||
const titleField = createAutofillFieldMock({ opid: "title", htmlName: "title" });
|
||||
const emailField = createAutofillFieldMock({ opid: "email", htmlName: "email" });
|
||||
pageDetails.fields = [titleField, emailField];
|
||||
const title = "Mr.";
|
||||
const email = "email@example.com";
|
||||
options.cipher.identity.title = title;
|
||||
options.cipher.identity.email = email;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity.title,
|
||||
titleField,
|
||||
filledFields,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity.email,
|
||||
emailField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", titleField.opid, title]);
|
||||
expect(value.script[5]).toStrictEqual(["fill_by_opid", emailField.opid, email]);
|
||||
});
|
||||
|
||||
it("will match a full address field to the vault item identity values", async () => {
|
||||
const fullAddressField = createAutofillFieldMock({
|
||||
opid: "fullAddress",
|
||||
htmlName: "address",
|
||||
});
|
||||
pageDetails.fields = [fullAddressField];
|
||||
const address1 = "123 Main St.";
|
||||
const address2 = "Apt. 1";
|
||||
const address3 = "P.O. Box 123";
|
||||
options.cipher.identity.address1 = address1;
|
||||
options.cipher.identity.address2 = address2;
|
||||
options.cipher.identity.address3 = address3;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
`${address1}, ${address2}, ${address3}`,
|
||||
fullAddressField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual([
|
||||
"fill_by_opid",
|
||||
fullAddressField.opid,
|
||||
`${address1}, ${address2}, ${address3}`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("will match address1, address2, address3, postalCode, city, state, country, phone, username, and company fields to their corresponding vault item identity values", async () => {
|
||||
const address1Field = createAutofillFieldMock({
|
||||
opid: "address1",
|
||||
htmlName: "address-1",
|
||||
});
|
||||
const address2Field = createAutofillFieldMock({
|
||||
opid: "address2",
|
||||
htmlName: "address-2",
|
||||
});
|
||||
const address3Field = createAutofillFieldMock({
|
||||
opid: "address3",
|
||||
htmlName: "address-3",
|
||||
});
|
||||
const postalCodeField = createAutofillFieldMock({
|
||||
opid: "postalCode",
|
||||
htmlName: "postal-code",
|
||||
});
|
||||
const cityField = createAutofillFieldMock({ opid: "city", htmlName: "city" });
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
const countryField = createAutofillFieldMock({ opid: "country", htmlName: "country" });
|
||||
const phoneField = createAutofillFieldMock({ opid: "phone", htmlName: "phone" });
|
||||
const usernameField = createAutofillFieldMock({
|
||||
opid: "username",
|
||||
htmlName: "username",
|
||||
});
|
||||
const companyField = createAutofillFieldMock({ opid: "company", htmlName: "company" });
|
||||
pageDetails.fields = [
|
||||
address1Field,
|
||||
address2Field,
|
||||
address3Field,
|
||||
postalCodeField,
|
||||
cityField,
|
||||
stateField,
|
||||
countryField,
|
||||
phoneField,
|
||||
usernameField,
|
||||
companyField,
|
||||
];
|
||||
const address1 = "123 Main St.";
|
||||
const address2 = "Apt. 1";
|
||||
const address3 = "P.O. Box 123";
|
||||
const postalCode = "12345";
|
||||
const city = "City";
|
||||
const state = "TX";
|
||||
const country = "US";
|
||||
const phone = "123-456-7890";
|
||||
const username = "username";
|
||||
const company = "Company";
|
||||
options.cipher.identity.address1 = address1;
|
||||
options.cipher.identity.address2 = address2;
|
||||
options.cipher.identity.address3 = address3;
|
||||
options.cipher.identity.postalCode = postalCode;
|
||||
options.cipher.identity.city = city;
|
||||
options.cipher.identity.state = state;
|
||||
options.cipher.identity.country = country;
|
||||
options.cipher.identity.phone = phone;
|
||||
options.cipher.identity.username = username;
|
||||
options.cipher.identity.company = company;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(value.script).toContainEqual(["fill_by_opid", address1Field.opid, address1]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", address2Field.opid, address2]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", address3Field.opid, address3]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", postalCodeField.opid, postalCode]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", cityField.opid, city]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", stateField.opid, state]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", countryField.opid, country]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", phoneField.opid, phone]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", usernameField.opid, username]);
|
||||
expect(value.script).toContainEqual(["fill_by_opid", companyField.opid, company]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoState value for an identity cipher that contains the full name of a state", async () => {
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
pageDetails.fields = [stateField];
|
||||
const state = "California";
|
||||
options.cipher.identity.state = state;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"CA",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", stateField.opid, "CA"]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoProvince value for an identity cipher that contains the full name of a province", async () => {
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
pageDetails.fields = [stateField];
|
||||
const state = "Ontario";
|
||||
options.cipher.identity.state = state;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"ON",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", stateField.opid, "ON"]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoCountry value for an identity cipher that contains the full name of a country", async () => {
|
||||
const countryField = createAutofillFieldMock({ opid: "country", htmlName: "country" });
|
||||
pageDetails.fields = [countryField];
|
||||
const country = "Somalia";
|
||||
options.cipher.identity.country = country;
|
||||
|
||||
const value = await autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"SO",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", countryField.opid, "SO"]);
|
||||
});
|
||||
});
|
||||
const middleNameField = createAutofillFieldMock({
|
||||
opid: "middleName",
|
||||
htmlName: "middle-name",
|
||||
});
|
||||
const lastNameField = createAutofillFieldMock({ opid: "lastName", htmlName: "last-name" });
|
||||
pageDetails.fields = [firstNameField, middleNameField, lastNameField];
|
||||
options.cipher.identity.firstName = firstName;
|
||||
options.cipher.identity.middleName = middleName;
|
||||
options.cipher.identity.lastName = lastName;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
firstNameField.htmlName,
|
||||
IdentityAutoFillConstants.FirstnameFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
middleNameField.htmlName,
|
||||
IdentityAutoFillConstants.MiddlenameFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
lastNameField.htmlName,
|
||||
IdentityAutoFillConstants.LastnameFieldNames,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity,
|
||||
expect.anything(),
|
||||
filledFields,
|
||||
firstNameField.opid,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity,
|
||||
expect.anything(),
|
||||
filledFields,
|
||||
middleNameField.opid,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity,
|
||||
expect.anything(),
|
||||
filledFields,
|
||||
lastNameField.opid,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", firstNameField.opid, firstName]);
|
||||
expect(value.script[5]).toStrictEqual(["fill_by_opid", middleNameField.opid, middleName]);
|
||||
expect(value.script[8]).toStrictEqual(["fill_by_opid", lastNameField.opid, lastName]);
|
||||
});
|
||||
|
||||
it("will match title and email fields to the vault item identity value", () => {
|
||||
const titleField = createAutofillFieldMock({ opid: "title", htmlName: "title" });
|
||||
const emailField = createAutofillFieldMock({ opid: "email", htmlName: "email" });
|
||||
pageDetails.fields = [titleField, emailField];
|
||||
const title = "Mr.";
|
||||
const email = "email@example.com";
|
||||
options.cipher.identity.title = title;
|
||||
options.cipher.identity.email = email;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
titleField.htmlName,
|
||||
IdentityAutoFillConstants.TitleFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
emailField.htmlName,
|
||||
IdentityAutoFillConstants.EmailFieldNames,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity,
|
||||
expect.anything(),
|
||||
filledFields,
|
||||
titleField.opid,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
options.cipher.identity,
|
||||
expect.anything(),
|
||||
filledFields,
|
||||
emailField.opid,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", titleField.opid, title]);
|
||||
expect(value.script[5]).toStrictEqual(["fill_by_opid", emailField.opid, email]);
|
||||
});
|
||||
|
||||
it("will match a full address field to the vault item identity values", () => {
|
||||
const fullAddressField = createAutofillFieldMock({
|
||||
opid: "fullAddress",
|
||||
htmlName: "address",
|
||||
});
|
||||
pageDetails.fields = [fullAddressField];
|
||||
const address1 = "123 Main St.";
|
||||
const address2 = "Apt. 1";
|
||||
const address3 = "P.O. Box 123";
|
||||
options.cipher.identity.address1 = address1;
|
||||
options.cipher.identity.address2 = address2;
|
||||
options.cipher.identity.address3 = address3;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
fullAddressField.htmlName,
|
||||
IdentityAutoFillConstants.AddressFieldNames,
|
||||
IdentityAutoFillConstants.AddressFieldNameValues,
|
||||
);
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
`${address1}, ${address2}, ${address3}`,
|
||||
fullAddressField,
|
||||
filledFields,
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual([
|
||||
"fill_by_opid",
|
||||
fullAddressField.opid,
|
||||
`${address1}, ${address2}, ${address3}`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("will match address1, address2, address3, postalCode, city, state, country, phone, username, and company fields to their corresponding vault item identity values", () => {
|
||||
const address1Field = createAutofillFieldMock({ opid: "address1", htmlName: "address-1" });
|
||||
const address2Field = createAutofillFieldMock({ opid: "address2", htmlName: "address-2" });
|
||||
const address3Field = createAutofillFieldMock({ opid: "address3", htmlName: "address-3" });
|
||||
const postalCodeField = createAutofillFieldMock({
|
||||
opid: "postalCode",
|
||||
htmlName: "postal-code",
|
||||
});
|
||||
const cityField = createAutofillFieldMock({ opid: "city", htmlName: "city" });
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
const countryField = createAutofillFieldMock({ opid: "country", htmlName: "country" });
|
||||
const phoneField = createAutofillFieldMock({ opid: "phone", htmlName: "phone" });
|
||||
const usernameField = createAutofillFieldMock({ opid: "username", htmlName: "username" });
|
||||
const companyField = createAutofillFieldMock({ opid: "company", htmlName: "company" });
|
||||
pageDetails.fields = [
|
||||
address1Field,
|
||||
address2Field,
|
||||
address3Field,
|
||||
postalCodeField,
|
||||
cityField,
|
||||
stateField,
|
||||
countryField,
|
||||
phoneField,
|
||||
usernameField,
|
||||
companyField,
|
||||
];
|
||||
const address1 = "123 Main St.";
|
||||
const address2 = "Apt. 1";
|
||||
const address3 = "P.O. Box 123";
|
||||
const postalCode = "12345";
|
||||
const city = "City";
|
||||
const state = "State";
|
||||
const country = "Country";
|
||||
const phone = "123-456-7890";
|
||||
const username = "username";
|
||||
const company = "Company";
|
||||
options.cipher.identity.address1 = address1;
|
||||
options.cipher.identity.address2 = address2;
|
||||
options.cipher.identity.address3 = address3;
|
||||
options.cipher.identity.postalCode = postalCode;
|
||||
options.cipher.identity.city = city;
|
||||
options.cipher.identity.state = state;
|
||||
options.cipher.identity.country = country;
|
||||
options.cipher.identity.phone = phone;
|
||||
options.cipher.identity.username = username;
|
||||
options.cipher.identity.company = company;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
address1Field.htmlName,
|
||||
IdentityAutoFillConstants.Address1FieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
address2Field.htmlName,
|
||||
IdentityAutoFillConstants.Address2FieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
address3Field.htmlName,
|
||||
IdentityAutoFillConstants.Address3FieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
postalCodeField.htmlName,
|
||||
IdentityAutoFillConstants.PostalCodeFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
cityField.htmlName,
|
||||
IdentityAutoFillConstants.CityFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
stateField.htmlName,
|
||||
IdentityAutoFillConstants.StateFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
countryField.htmlName,
|
||||
IdentityAutoFillConstants.CountryFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
phoneField.htmlName,
|
||||
IdentityAutoFillConstants.PhoneFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
usernameField.htmlName,
|
||||
IdentityAutoFillConstants.UserNameFieldNames,
|
||||
);
|
||||
expect(AutofillService["isFieldMatch"]).toHaveBeenCalledWith(
|
||||
companyField.htmlName,
|
||||
IdentityAutoFillConstants.CompanyFieldNames,
|
||||
);
|
||||
expect(autofillService["makeScriptAction"]).toHaveBeenCalled();
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", address1Field.opid, address1]);
|
||||
expect(value.script[5]).toStrictEqual(["fill_by_opid", address2Field.opid, address2]);
|
||||
expect(value.script[8]).toStrictEqual(["fill_by_opid", address3Field.opid, address3]);
|
||||
expect(value.script[11]).toStrictEqual(["fill_by_opid", cityField.opid, city]);
|
||||
expect(value.script[14]).toStrictEqual(["fill_by_opid", postalCodeField.opid, postalCode]);
|
||||
expect(value.script[17]).toStrictEqual(["fill_by_opid", companyField.opid, company]);
|
||||
expect(value.script[20]).toStrictEqual(["fill_by_opid", phoneField.opid, phone]);
|
||||
expect(value.script[23]).toStrictEqual(["fill_by_opid", usernameField.opid, username]);
|
||||
expect(value.script[26]).toStrictEqual(["fill_by_opid", stateField.opid, state]);
|
||||
expect(value.script[29]).toStrictEqual(["fill_by_opid", countryField.opid, country]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoState value for an identity cipher that contains the full name of a state", () => {
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
pageDetails.fields = [stateField];
|
||||
const state = "California";
|
||||
options.cipher.identity.state = state;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"CA",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", stateField.opid, "CA"]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoProvince value for an identity cipher that contains the full name of a province", () => {
|
||||
const stateField = createAutofillFieldMock({ opid: "state", htmlName: "state" });
|
||||
pageDetails.fields = [stateField];
|
||||
const state = "Ontario";
|
||||
options.cipher.identity.state = state;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"ON",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", stateField.opid, "ON"]);
|
||||
});
|
||||
|
||||
it("will find the two character IsoCountry value for an identity cipher that contains the full name of a country", () => {
|
||||
const countryField = createAutofillFieldMock({ opid: "country", htmlName: "country" });
|
||||
pageDetails.fields = [countryField];
|
||||
const country = "Somalia";
|
||||
options.cipher.identity.country = country;
|
||||
|
||||
const value = autofillService["generateIdentityFillScript"](
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
options,
|
||||
);
|
||||
|
||||
expect(autofillService["makeScriptActionWithValue"]).toHaveBeenCalledWith(
|
||||
fillScript,
|
||||
"SO",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(value.script[2]).toStrictEqual(["fill_by_opid", countryField.opid, "SO"]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import { FieldType, CipherType } from "@bitwarden/common/vault/enums";
|
|||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FieldView } from "@bitwarden/common/vault/models/view/field.view";
|
||||
import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view";
|
||||
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service";
|
||||
|
@ -478,6 +479,12 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||
return totpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cipher requires password reprompt and opens the password reprompt popout if necessary.
|
||||
*
|
||||
* @param cipher - The cipher to autofill
|
||||
* @param tab - The tab to autofill
|
||||
*/
|
||||
async isPasswordRepromptRequired(cipher: CipherView, tab: chrome.tabs.Tab): Promise<boolean> {
|
||||
const userHasMasterPasswordAndKeyHash =
|
||||
await this.userVerificationService.hasMasterPasswordAndMasterKeyHash();
|
||||
|
@ -654,7 +661,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||
fillScript = this.generateCardFillScript(fillScript, pageDetails, filledFields, options);
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
fillScript = this.generateIdentityFillScript(
|
||||
fillScript = await this.generateIdentityFillScript(
|
||||
fillScript,
|
||||
pageDetails,
|
||||
filledFields,
|
||||
|
@ -1243,12 +1250,16 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||
* @returns {AutofillScript}
|
||||
* @private
|
||||
*/
|
||||
private generateIdentityFillScript(
|
||||
private async generateIdentityFillScript(
|
||||
fillScript: AutofillScript,
|
||||
pageDetails: AutofillPageDetails,
|
||||
filledFields: { [id: string]: AutofillField },
|
||||
options: GenerateFillScriptOptions,
|
||||
): AutofillScript {
|
||||
): Promise<AutofillScript> {
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.GenerateIdentityFillScriptRefactor)) {
|
||||
return this._generateIdentityFillScript(fillScript, pageDetails, filledFields, options);
|
||||
}
|
||||
|
||||
if (!options.cipher.identity) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1476,6 +1487,589 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||
return fillScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the autofill script for the specified page details and identity cipher item.
|
||||
*
|
||||
* @param fillScript - Object to store autofill script, passed between method references
|
||||
* @param pageDetails - The details of the page to autofill
|
||||
* @param filledFields - The fields that have already been filled, passed between method references
|
||||
* @param options - Contains data used to fill cipher items
|
||||
*/
|
||||
private _generateIdentityFillScript(
|
||||
fillScript: AutofillScript,
|
||||
pageDetails: AutofillPageDetails,
|
||||
filledFields: { [id: string]: AutofillField },
|
||||
options: GenerateFillScriptOptions,
|
||||
): AutofillScript {
|
||||
const identity = options.cipher.identity;
|
||||
if (!identity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let fieldsIndex = 0; fieldsIndex < pageDetails.fields.length; fieldsIndex++) {
|
||||
const field = pageDetails.fields[fieldsIndex];
|
||||
if (this.excludeFieldFromIdentityFill(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const keywordsList = this.getIdentityAutofillFieldKeywords(field);
|
||||
const keywordsCombined = keywordsList.join(",");
|
||||
if (this.shouldMakeIdentityTitleFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.title, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityNameFillScript(filledFields, keywordsList)) {
|
||||
this.makeIdentityNameFillScript(fillScript, filledFields, field, identity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityFirstNameFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.firstName, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityMiddleNameFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.middleName, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityLastNameFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.lastName, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityEmailFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.email, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityAddressFillScript(filledFields, keywordsList)) {
|
||||
this.makeIdentityAddressFillScript(fillScript, filledFields, field, identity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityAddress1FillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.address1, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityAddress2FillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.address2, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityAddress3FillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.address3, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityPostalCodeFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.postalCode, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityCityFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.city, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityStateFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeIdentityStateFillScript(fillScript, filledFields, field, identity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityCountryFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeIdentityCountryFillScript(fillScript, filledFields, field, identity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityPhoneFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.phone, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityUserNameFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.username, field, filledFields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldMakeIdentityCompanyFillScript(filledFields, keywordsCombined)) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.company, field, filledFields);
|
||||
}
|
||||
}
|
||||
|
||||
return fillScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if the current field should be excluded from triggering autofill of the identity cipher.
|
||||
*
|
||||
* @param field - The field to check
|
||||
*/
|
||||
private excludeFieldFromIdentityFill(field: AutofillField): boolean {
|
||||
return (
|
||||
AutofillService.isExcludedFieldType(field, AutoFillConstants.ExcludedAutofillTypes) ||
|
||||
AutoFillConstants.ExcludedIdentityAutocompleteTypes.has(field.autoCompleteType) ||
|
||||
!field.viewable
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers all unique keyword identifiers from a field that can be used to determine what
|
||||
* identity value should be filled.
|
||||
*
|
||||
* @param field - The field to gather keywords from
|
||||
*/
|
||||
private getIdentityAutofillFieldKeywords(field: AutofillField): string[] {
|
||||
const keywords: Set<string> = new Set();
|
||||
for (let index = 0; index < IdentityAutoFillConstants.IdentityAttributes.length; index++) {
|
||||
const attribute = IdentityAutoFillConstants.IdentityAttributes[index];
|
||||
if (field[attribute]) {
|
||||
keywords.add(
|
||||
field[attribute]
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[^a-zA-Z0-9]+/g, ""),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(keywords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity title
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityTitleFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.title &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.TitleFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity name
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityNameFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string[],
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.name &&
|
||||
keywords.some((keyword) =>
|
||||
AutofillService.isFieldMatch(
|
||||
keyword,
|
||||
IdentityAutoFillConstants.FullNameFieldNames,
|
||||
IdentityAutoFillConstants.FullNameFieldNameValues,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity first name
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityFirstNameFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.firstName &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.FirstnameFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity middle name
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityMiddleNameFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.middleName &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.MiddlenameFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity last name
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityLastNameFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.lastName &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.LastnameFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity email
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityEmailFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.email &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.EmailFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity address
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityAddressFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string[],
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.address &&
|
||||
keywords.some((keyword) =>
|
||||
AutofillService.isFieldMatch(
|
||||
keyword,
|
||||
IdentityAutoFillConstants.AddressFieldNames,
|
||||
IdentityAutoFillConstants.AddressFieldNameValues,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity address1
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityAddress1FillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.address1 &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.Address1FieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity address2
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityAddress2FillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.address2 &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.Address2FieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity address3
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityAddress3FillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.address3 &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.Address3FieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity postal code
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityPostalCodeFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.postalCode &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.PostalCodeFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity city
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityCityFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.city &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.CityFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity state
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityStateFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.state &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.StateFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity country
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityCountryFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.country &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.CountryFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity phone
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityPhoneFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.phone &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.PhoneFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity username
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityUserNameFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.username &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.UserNameFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a fill script action for the identity company
|
||||
* field should be created for the provided field.
|
||||
*
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param keywords - The keywords from the field
|
||||
*/
|
||||
private shouldMakeIdentityCompanyFillScript(
|
||||
filledFields: Record<string, AutofillField>,
|
||||
keywords: string,
|
||||
): boolean {
|
||||
return (
|
||||
!filledFields.company &&
|
||||
AutofillService.isFieldMatch(keywords, IdentityAutoFillConstants.CompanyFieldNames)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity name fill script action for the provided field. This is used
|
||||
* when filling a `full name` field, using the first, middle, and last name from the
|
||||
* identity cipher item.
|
||||
*
|
||||
* @param fillScript - The autofill script to add the action to
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param field - The field to fill
|
||||
* @param identity - The identity cipher item
|
||||
*/
|
||||
private makeIdentityNameFillScript(
|
||||
fillScript: AutofillScript,
|
||||
filledFields: Record<string, AutofillField>,
|
||||
field: AutofillField,
|
||||
identity: IdentityView,
|
||||
) {
|
||||
let name = "";
|
||||
if (identity.firstName) {
|
||||
name += identity.firstName;
|
||||
}
|
||||
|
||||
if (identity.middleName) {
|
||||
name += !name ? identity.middleName : ` ${identity.middleName}`;
|
||||
}
|
||||
|
||||
if (identity.lastName) {
|
||||
name += !name ? identity.lastName : ` ${identity.lastName}`;
|
||||
}
|
||||
|
||||
this.makeScriptActionWithValue(fillScript, name, field, filledFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity address fill script action for the provided field. This is used
|
||||
* when filling a generic `address` field, using the address1, address2, and address3
|
||||
* from the identity cipher item.
|
||||
*
|
||||
* @param fillScript - The autofill script to add the action to
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param field - The field to fill
|
||||
* @param identity - The identity cipher item
|
||||
*/
|
||||
private makeIdentityAddressFillScript(
|
||||
fillScript: AutofillScript,
|
||||
filledFields: Record<string, AutofillField>,
|
||||
field: AutofillField,
|
||||
identity: IdentityView,
|
||||
) {
|
||||
if (!identity.address1) {
|
||||
return;
|
||||
}
|
||||
|
||||
let address = identity.address1;
|
||||
|
||||
if (identity.address2) {
|
||||
address += `, ${identity.address2}`;
|
||||
}
|
||||
|
||||
if (identity.address3) {
|
||||
address += `, ${identity.address3}`;
|
||||
}
|
||||
|
||||
this.makeScriptActionWithValue(fillScript, address, field, filledFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity state fill script action for the provided field. This is used
|
||||
* when filling a `state` field, using the state value from the identity cipher item.
|
||||
* If the state value is a full name, it will be converted to an ISO code.
|
||||
*
|
||||
* @param fillScript - The autofill script to add the action to
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param field - The field to fill
|
||||
* @param identity - The identity cipher item
|
||||
*/
|
||||
private makeIdentityStateFillScript(
|
||||
fillScript: AutofillScript,
|
||||
filledFields: Record<string, AutofillField>,
|
||||
field: AutofillField,
|
||||
identity: IdentityView,
|
||||
) {
|
||||
if (!identity.state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (identity.state.length <= 2) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.state, field, filledFields);
|
||||
return;
|
||||
}
|
||||
|
||||
const stateLower = identity.state.toLowerCase();
|
||||
const isoState =
|
||||
IdentityAutoFillConstants.IsoStates[stateLower] ||
|
||||
IdentityAutoFillConstants.IsoProvinces[stateLower];
|
||||
if (isoState) {
|
||||
this.makeScriptActionWithValue(fillScript, isoState, field, filledFields);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity country fill script action for the provided field. This is used
|
||||
* when filling a `country` field, using the country value from the identity cipher item.
|
||||
* If the country value is a full name, it will be converted to an ISO code.
|
||||
*
|
||||
* @param fillScript - The autofill script to add the action to
|
||||
* @param filledFields - The fields that have already been filled
|
||||
* @param field - The field to fill
|
||||
* @param identity - The identity cipher item
|
||||
*/
|
||||
private makeIdentityCountryFillScript(
|
||||
fillScript: AutofillScript,
|
||||
filledFields: Record<string, AutofillField>,
|
||||
field: AutofillField,
|
||||
identity: IdentityView,
|
||||
) {
|
||||
if (!identity.country) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (identity.country.length <= 2) {
|
||||
this.makeScriptActionWithValue(fillScript, identity.country, field, filledFields);
|
||||
return;
|
||||
}
|
||||
|
||||
const countryLower = identity.country.toLowerCase();
|
||||
const isoCountry = IdentityAutoFillConstants.IsoCountries[countryLower];
|
||||
if (isoCountry) {
|
||||
this.makeScriptActionWithValue(fillScript, isoCountry, field, filledFields);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an HTMLInputElement type value and a list of
|
||||
* excluded types and returns true if the type is excluded.
|
||||
|
|
|
@ -1057,7 +1057,7 @@ export class InlineMenuFieldQualificationService
|
|||
returnStringValue: boolean,
|
||||
) {
|
||||
if (!this.autofillFieldKeywordsMap.has(autofillFieldData)) {
|
||||
const keywords = [
|
||||
const keywordsSet = new Set<string>([
|
||||
autofillFieldData.htmlID,
|
||||
autofillFieldData.htmlName,
|
||||
autofillFieldData.htmlClass,
|
||||
|
@ -1071,9 +1071,8 @@ export class InlineMenuFieldQualificationService
|
|||
autofillFieldData["label-right"],
|
||||
autofillFieldData["label-tag"],
|
||||
autofillFieldData["label-top"],
|
||||
];
|
||||
const keywordsSet = new Set<string>(keywords);
|
||||
const stringValue = keywords.join(",").toLowerCase();
|
||||
]);
|
||||
const stringValue = Array.from(keywordsSet).join(",").toLowerCase();
|
||||
this.autofillFieldKeywordsMap.set(autofillFieldData, { keywordsSet, stringValue });
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ export enum FeatureFlag {
|
|||
AuthenticatorTwoFactorToken = "authenticator-2fa-token",
|
||||
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
||||
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
||||
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
||||
}
|
||||
|
||||
export type AllowedFeatureFlagTypes = boolean | number | string;
|
||||
|
@ -68,6 +69,7 @@ export const DefaultFeatureFlagValue = {
|
|||
[FeatureFlag.AuthenticatorTwoFactorToken]: FALSE,
|
||||
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
||||
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
||||
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
||||
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
|
||||
|
||||
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;
|
||||
|
|
Loading…
Reference in New Issue