[PM-8841] Passkeys script injection breaks loading of specific websites that are expecting an empty DOM on init (#10424)
* [PM-8841] Passkeys script injection breaks loading of specific websites that are expecting an empty DOM on init * [PM-8841] Implementing feature flag to allow for dynamic registration of the delayed page-script-append mv2 script
This commit is contained in:
parent
66d9ab5dc0
commit
f51d1ba101
|
@ -1,6 +1,7 @@
|
|||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
CreateCredentialParams,
|
||||
|
@ -54,6 +55,7 @@ describe("Fido2Background", () => {
|
|||
let fido2ClientService!: MockProxy<Fido2ClientService>;
|
||||
let vaultSettingsService!: MockProxy<VaultSettingsService>;
|
||||
let scriptInjectorServiceMock!: MockProxy<BrowserScriptInjectorService>;
|
||||
let configServiceMock!: MockProxy<ConfigService>;
|
||||
let enablePasskeysMock$!: BehaviorSubject<boolean>;
|
||||
let fido2Background!: Fido2Background;
|
||||
|
||||
|
@ -71,6 +73,7 @@ describe("Fido2Background", () => {
|
|||
abortController = mock<AbortController>();
|
||||
registeredContentScripsMock = mock<browser.contentScripts.RegisteredContentScript>();
|
||||
scriptInjectorServiceMock = mock<BrowserScriptInjectorService>();
|
||||
configServiceMock = mock<ConfigService>();
|
||||
|
||||
enablePasskeysMock$ = new BehaviorSubject(true);
|
||||
vaultSettingsService.enablePasskeys$ = enablePasskeysMock$;
|
||||
|
@ -80,6 +83,7 @@ describe("Fido2Background", () => {
|
|||
fido2ClientService,
|
||||
vaultSettingsService,
|
||||
scriptInjectorServiceMock,
|
||||
configServiceMock,
|
||||
);
|
||||
fido2Background["abortManager"] = abortManagerMock;
|
||||
abortManagerMock.runWithAbortController.mockImplementation((_requestId, runner) =>
|
||||
|
@ -110,6 +114,7 @@ describe("Fido2Background", () => {
|
|||
tabsQuerySpy.mockResolvedValueOnce([tabMock, secondTabMock, insecureTab, noUrlTab]);
|
||||
|
||||
await fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
await flushPromises();
|
||||
|
||||
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
|
||||
tabId: tabMock.id,
|
||||
|
@ -133,6 +138,7 @@ describe("Fido2Background", () => {
|
|||
tabsQuerySpy.mockResolvedValueOnce([tabMock]);
|
||||
|
||||
await fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
await flushPromises();
|
||||
|
||||
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
|
||||
tabId: tabMock.id,
|
||||
|
@ -206,6 +212,22 @@ describe("Fido2Background", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("registers the page-script-delay-append-mv2.js content script when the DelayFido2PageScriptInitWithinMv2 feature flag is enabled", async () => {
|
||||
configServiceMock.getFeatureFlag.mockResolvedValue(true);
|
||||
isManifestVersionSpy.mockImplementation((manifestVersion) => manifestVersion === 2);
|
||||
|
||||
enablePasskeysMock$.next(true);
|
||||
await flushPromises();
|
||||
|
||||
expect(BrowserApi.registerContentScriptsMv2).toHaveBeenCalledWith({
|
||||
js: [
|
||||
{ file: Fido2ContentScript.PageScriptDelayAppend },
|
||||
{ file: Fido2ContentScript.ContentScript },
|
||||
],
|
||||
...sharedRegistrationOptions,
|
||||
});
|
||||
});
|
||||
|
||||
it("unregisters any existing registered content scripts when the enablePasskeys setting is set to `false`", async () => {
|
||||
isManifestVersionSpy.mockImplementation((manifestVersion) => manifestVersion === 2);
|
||||
fido2Background["registeredContentScripts"] = registeredContentScripsMock;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { firstValueFrom, startWith } from "rxjs";
|
||||
import { pairwise } from "rxjs/operators";
|
||||
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
AssertCredentialResult,
|
||||
|
@ -50,6 +52,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||
private fido2ClientService: Fido2ClientService,
|
||||
private vaultSettingsService: VaultSettingsService,
|
||||
private scriptInjectorService: ScriptInjectorService,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -132,7 +135,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||
|
||||
this.registeredContentScripts = await BrowserApi.registerContentScriptsMv2({
|
||||
js: [
|
||||
{ file: Fido2ContentScript.PageScriptAppend },
|
||||
{ file: await this.getFido2PageScriptAppendFileName() },
|
||||
{ file: Fido2ContentScript.ContentScript },
|
||||
],
|
||||
...this.sharedRegistrationOptions,
|
||||
|
@ -176,7 +179,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||
void this.scriptInjectorService.inject({
|
||||
tabId: tab.id,
|
||||
injectDetails: { frame: "all_frames", ...this.sharedInjectionDetails },
|
||||
mv2Details: { file: Fido2ContentScript.PageScriptAppend },
|
||||
mv2Details: { file: await this.getFido2PageScriptAppendFileName() },
|
||||
mv3Details: { file: Fido2ContentScript.PageScript, world: "MAIN" },
|
||||
});
|
||||
|
||||
|
@ -353,4 +356,20 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||
|
||||
this.fido2ContentScriptPortsSet.delete(port);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the file name of the page-script used within mv2. Will return the
|
||||
* delayed append script if the associated feature flag is enabled.
|
||||
*/
|
||||
private async getFido2PageScriptAppendFileName() {
|
||||
const shouldDelayInit = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.DelayFido2PageScriptInitWithinMv2,
|
||||
);
|
||||
|
||||
if (shouldDelayInit) {
|
||||
return Fido2ContentScript.PageScriptDelayAppend;
|
||||
}
|
||||
|
||||
return Fido2ContentScript.PageScriptAppend;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This script handles injection of the FIDO2 override page script into the document.
|
||||
* This is required for manifest v2, but will be removed when we migrate fully to manifest v3.
|
||||
*/
|
||||
import { Fido2ContentScript } from "../enums/fido2-content-script.enum";
|
||||
|
||||
(function (globalContext) {
|
||||
if (globalContext.document.contentType !== "text/html") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (globalContext.document.readyState === "complete") {
|
||||
loadScript();
|
||||
} else {
|
||||
globalContext.addEventListener("DOMContentLoaded", loadScript);
|
||||
}
|
||||
|
||||
function loadScript() {
|
||||
const script = globalContext.document.createElement("script");
|
||||
script.src = chrome.runtime.getURL(Fido2ContentScript.PageScript);
|
||||
script.addEventListener("load", () => script.remove());
|
||||
|
||||
const scriptInsertionPoint =
|
||||
globalContext.document.head || globalContext.document.documentElement;
|
||||
scriptInsertionPoint.insertBefore(script, scriptInsertionPoint.firstChild);
|
||||
}
|
||||
})(globalThis);
|
|
@ -1,6 +1,7 @@
|
|||
export const Fido2ContentScript = {
|
||||
PageScript: "content/fido2-page-script.js",
|
||||
PageScriptAppend: "content/fido2-page-script-append-mv2.js",
|
||||
PageScriptDelayAppend: "content/fido2-page-script-delay-append-mv2.js",
|
||||
ContentScript: "content/fido2-content-script.js",
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -1025,6 +1025,7 @@ export default class MainBackground {
|
|||
this.fido2ClientService,
|
||||
this.vaultSettingsService,
|
||||
this.scriptInjectorService,
|
||||
this.configService,
|
||||
);
|
||||
this.runtimeBackground = new RuntimeBackground(
|
||||
this,
|
||||
|
|
|
@ -301,6 +301,8 @@ if (manifestVersion == 2) {
|
|||
"./src/tools/content/lp-suppress-import-download-script-append.mv2.ts";
|
||||
mainConfig.entry["content/fido2-page-script-append-mv2"] =
|
||||
"./src/autofill/fido2/content/fido2-page-script-append.mv2.ts";
|
||||
mainConfig.entry["content/fido2-page-script-delay-append-mv2"] =
|
||||
"./src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts";
|
||||
|
||||
configs.push(mainConfig);
|
||||
} else {
|
||||
|
|
|
@ -30,6 +30,7 @@ export enum FeatureFlag {
|
|||
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
||||
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
||||
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
||||
DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2",
|
||||
}
|
||||
|
||||
export type AllowedFeatureFlagTypes = boolean | number | string;
|
||||
|
@ -70,6 +71,7 @@ export const DefaultFeatureFlagValue = {
|
|||
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
||||
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
||||
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
||||
[FeatureFlag.DelayFido2PageScriptInitWithinMv2]: FALSE,
|
||||
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
|
||||
|
||||
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;
|
||||
|
|
Loading…
Reference in New Issue