diff --git a/apps/browser/src/autofill/services/autofill-constants.ts b/apps/browser/src/autofill/services/autofill-constants.ts index 3a297e8d251..22b248be77b 100644 --- a/apps/browser/src/autofill/services/autofill-constants.ts +++ b/apps/browser/src/autofill/services/autofill-constants.ts @@ -76,6 +76,11 @@ export class AutoFillConstants { "textarea", ...AutoFillConstants.ExcludedAutofillTypes, ]; + + static readonly ExcludedIdentityAutocompleteTypes: Set = new Set([ + "current-password", + "new-password", + ]); } export class CreditCardAutoFillConstants { diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts index 1ceebe53fca..aca82227284 100644 --- a/apps/browser/src/autofill/services/autofill.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill.service.spec.ts @@ -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(); }); - 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); - - 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([]); - }); - - 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 = 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([]); - }); - - it("will not attempt to match a field that is not viewable", () => { - const viewableField = createAutofillFieldMock({ viewable: false }); - pageDetails.fields.push(viewableField); - - 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([]); - }); - - 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 = autofillService["generateIdentityFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); + let isRefactorFeatureFlagSet = false; + for (let index = 0; index < 2; index++) { + describe(`when the isRefactorFeatureFlagSet is ${isRefactorFeatureFlagSet}`, () => { + beforeEach(() => { + configService.getFeatureFlag.mockResolvedValue(isRefactorFeatureFlagSet); + }); - 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}`, - ]); - }); + afterAll(() => { + isRefactorFeatureFlagSet = true; + }); - 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; + it("will not attempt to match custom fields", async () => { + const customField = createAutofillFieldMock({ tagName: "span" }); + pageDetails.fields.push(customField); + + const value = await autofillService["generateIdentityFillScript"]( + fillScript, + pageDetails, + filledFields, + options, + ); + + expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(customField); + expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled(); + expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled(); + expect(value.script).toStrictEqual([]); + }); - const value = autofillService["generateIdentityFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); + it("will not attempt to match a field that is of an excluded type", async () => { + const excludedField = createAutofillFieldMock({ type: "hidden" }); + pageDetails.fields.push(excludedField); + + const value = await 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["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 not attempt to match a field that is not viewable", async () => { + const viewableField = createAutofillFieldMock({ viewable: false }); + pageDetails.fields.push(viewableField); + + const value = await autofillService["generateIdentityFillScript"]( + fillScript, + pageDetails, + filledFields, + options, + ); + + expect(AutofillService.forCustomFieldsOnly).toHaveBeenCalledWith(viewableField); + expect(AutofillService["isExcludedFieldType"]).toHaveBeenCalled(); + expect(AutofillService["isFieldMatch"]).not.toHaveBeenCalled(); + expect(value.script).toStrictEqual([]); + }); - 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 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; + 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; + + const value = await 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}`, + ]); + }); - const value = autofillService["generateIdentityFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); + 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; + + 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]); + }); - 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 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", () => { - 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; + 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]); + }); - const value = autofillService["generateIdentityFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); + 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}`, + ]); + }); - 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 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 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, - ); + 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"]); + }); - 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 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 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", + 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 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"]); - }); + } }); }); diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index f2ef9790f62..d9ae4e99237 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -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 { 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 { + 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 = 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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. 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 3c48d8db83f..1af8cd5bd28 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 @@ -1057,7 +1057,7 @@ export class InlineMenuFieldQualificationService returnStringValue: boolean, ) { if (!this.autofillFieldKeywordsMap.has(autofillFieldData)) { - const keywords = [ + const keywordsSet = new Set([ 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(keywords); - const stringValue = keywords.join(",").toLowerCase(); + ]); + const stringValue = Array.from(keywordsSet).join(",").toLowerCase(); this.autofillFieldKeywordsMap.set(autofillFieldData, { keywordsSet, stringValue }); } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index f077e5a554f..4b19251d979 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -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; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;