1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

[PM-5744] Adjust Fido2 Content Script Injection to Meet mv3 Requirements (#8222)

* [PM-5876] Adjust LP Fileless Importer to Suppress Download with DOM Append in Manifest v3

* [PM-5876] Incorporating jest tests for affected logic

* [PM-5876] Fixing jest test that leverages rxjs

* [PM-5876] Updating documentation within BrowserApi.executeScriptInTab

* [PM-5876] Implementing jest tests for the new LP suppress download content scripts

* [PM-5876] Adding a change to webpack to ensure we do not package the mv2 side script for `lp-suppress-import-download.mv2.ts` if building the extension for mv3

* [PM-5876] Implementing changes based on feedback during code review

* [PM-5876] Implementing changes based on feedback during code review

* [PM-5876] Implementing changes based on feedback during code review

* [PM-5876] Implementing changes based on feedback during code review

* [PM-5876] Implementing a configuration to feed the script injection of the Fileless Importer CSV download supression script

* [PM-5744] Adjust injection of `page-script.ts` within FIDO 2 implementation to ensure mv3 compatibility

* [PM-5744] Adjusting structure of manifest.json to clean up implementation and ensure consistency between mv2 and mv3

* [PM-5744] Reverting inclusion of the ConsoleLogService

* [PM-4791] Injected content scripts prevent proper XML file display and disrupt XML responses

* [PM-5744] Adjust FIDO2 content script injection methodology to be compatible with manifest v3

* [PM-5744] Adjusting references to Fido2Service to mirror change of name to Fido2Background

* [PM-5744] Migrating runtime background messages that are associated with Fido2 into Fido2Background

* [PM-5744] Fixing named reference within Fido2Background

* [PM-5744] Migrating all Fido2 messages from the runtime.background.ts script to the fido2.background.ts script

* [PM-5744] Removing unnecessary dependency from runtime background

* [PM-5744] Removing unnecessary dependency from runtime background

* [PM-5744] Reworking how we handle init of Fido2Background

* [PM-5744] Reworking page-script.ts to ensure that it can destory its global values on unload

* [PM-5744] Reworking page-script.ts to ensure that it can destory its global values on unload

* [PM-5744] Implementing separated injection methodology between manifest v2 and v3

* [PM-4791] Adjsuting reference for Fido2 script injection to ensure it only triggers on https protocol types

* [PM-5744] Removing unnecessary message and handling reload of content scripts based on updates on observable

* [PM-5744] Refactoring content-script implementation for fido2

* [PM-5744] Refactoring content-script implementation for fido2

* [PM-5744] Reworking implementation to avoid having multiple contenType checks within the FIDO2 content scripts

* [PM-5744] Re-implementing the messageWithResponse within runtime.background.ts

* [PM-5744] Reverting change to autofill.service.ts

* [PM-5744] Removing return value from runtime.background.ts process message call

* [PM-5744] Reworking how we handle injection of the fido2 page and content script elements

* [PM-5744] Adjusting how we override the navigator.credentials request/reponse structure

* [PM-5744] Working through jest tests for the fido2Background implementation

* [PM-5744] Finalizing jest tests for the Fido2Background implementation

* [PM-5744] Stubbing out jest tests for content-script and page-script

* [PM-5744] Implementing a methodology that allows us to dynamically set and unset content scripts

* [PM-5744] Applying cleanup to page-script.ts to lighten the footprint of the script

* [PM-5744] Further simplifying page-script implementation

* [PM-5744] Reworking Fido2Utils to remove references to the base Utils methods to allow the page-script.ts file to render at a lower file size

* [PM-5744] Reworking Fido2Utils to remove references to the base Utils methods to allow the page-script.ts file to render at a lower file size

* [PM-5744] Implementing the `RegisterContentScriptPolyfill` as a separately compiled file as opposed to an import

* [PM-5744] Implementing methodology to ensure that the RegisterContentScript polyfill is not built in cases where it is not needed

* [PM-5744] Implementing methodology to ensure that the RegisterContentScript polyfill is not built in cases where it is not needed

* [PM-5744] Reverting package-lock.json

* [PM-5744] Implementing a methodology to ensure we can instantiate the RegisterContentScript polyfill in a siloed manner

* [PM-5744] Migrating chrome extension api calls to the BrowserApi class

* [PM-5744] Implementing typing information within the RegisterContentScriptsPolyfill

* [PM-5744] Removing any eslint-disable references within the RegisterContentScriptsPolyfill

* [PM-5744] Refactoring polyfill implementation

* [PM-5744] Refactoring polyfill implementation

* [PM-5744] Fixing an issue where Safari was not resolving the await chrome proxy

* [PM-5744] Fixing jest tests for the page-script append method

* [PM-5744] Fixing an issue found where collection of page details can trigger a context invalidated message when the extension is refreshed

* [PM-5744] Implementing jest tests for the added BrowserApi methods

* [PM-5744] Refactoring Fido2Background implementation

* [PM-5744] Refactoring Fido2Background implementation

* [PM-5744] Adding enums to the implementation for the Fido2 Content Scripts and working through jest tests for the BrowserApi and Fido2Background classes

* [PM-5744] Adding comments to the FIDO2 content-script.ts file

* [PM-5744] Adding jest tests for the Fido2 content-script.ts

* [PM-5744] Adding jest tests for the Fido2 content-script.ts

* [PM-5744] Adding jest tests for the Fido2 page-script.ts

* [PM-5744] Working through an attempt to jest test the page-script.ts file

* [PM-5744] Finalizing jest tests for the page-script.ts implementation

* [PM-5744] Applying stricter type information for the passed params within fido2-testing-utils.ts

* [PM-5744] Adjusting documentation

* [PM-5744] Adjusting implementation of jest tests to use mock proxies

* [PM-5744] Adjusting jest tests to simply implementation

* [PM-5744] Adjust jest tests based on code review feedback

* [PM-5744] Adjust jest tests based on code review feedback

* [PM-5744] Adjust jest tests based on code review feedback

* [PM-5744] Adjusting jest tests to based on feedback

* [PM-5744] Adjusting jest tests to based on feedback

* [PM-5744] Adjusting jest tests to based on feedback

* [PM-5744] Adjusting conditional within page-script.ts

* [PM-5744] Removing unnecessary global reference to the messager

* [PM-5744] Updating jest tests

* [PM-5744] Updating jest tests

* [PM-5744] Updating jest tests

* [PM-5744] Updating jest tests

* [PM-5744] Updating how we export the Fido2Background class

* [PM-5744] Adding duplciate jest tests to fido2-utils.ts to ensure we maintain functionality for utils methods pulled from platform utils

* [PM-5189] Addressing code review feedback

* [PM-5744] Applying code review feedback, reworking obserable subscription within fido2 background

* [PM-5744] Reworking jest tests to avoid mocking `firstValueFrom`

* [PM-5744] Reworking jest tests to avoid usage of private methods

* [PM-5744] Reworking jest tests to avoid usage of private methods

* [PM-5744] Implementing jest tests for the ScriptInjectorService and updating references within the Browser Extension to use the new service

* [PM-5744] Converting ScriptInjectorService to a dependnecy instead of a static class

* [PM-5744] Reworking typing for the ScriptInjectorService

* [PM-5744] Adjusting implementation based on feedback provided during code review

* [PM-5744] Adjusting implementation based on feedback provided during code review

* [PM-5744] Adjusting implementation based on feedback provided during code review

* [PM-5744] Adjusting implementation based on feedback provided during code review

* [PM-5744] Adjusting how the ScriptInjectorService accepts the config to simplify the data structure

* [PM-5744] Updating jest tests to cover edge cases within ScriptInjectorService

* [PM-5744] Updating jest tests to reference the ScriptInjectorService directly rather than the underlying ExecuteScript api call

* [PM-5744] Updating jest tests to reflect provided feedback during code review

* [PM-5744] Updating jest tests to reflect provided feedback during code review

* [PM-5744] Updating documentation based on code review feedback

* [PM-5744] Updating how we extend the abstract ScriptInjectorService

* [PM-5744] Updating reference to the frame property on the ScriptInjectionConfig
This commit is contained in:
Cesar Gonzalez
2024-04-18 11:05:16 -05:00
committed by GitHub
parent 912b7c136e
commit 9277465951
48 changed files with 2767 additions and 564 deletions

View File

@@ -48,20 +48,26 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
) {}
async isFido2FeatureEnabled(hostname: string, origin: string): Promise<boolean> {
const userEnabledPasskeys = await firstValueFrom(this.vaultSettingsService.enablePasskeys$);
const isUserLoggedIn =
(await this.authService.getAuthStatus()) !== AuthenticationStatus.LoggedOut;
if (!isUserLoggedIn) {
return false;
}
const neverDomains = await firstValueFrom(this.domainSettingsService.neverDomains$);
const isExcludedDomain = neverDomains != null && hostname in neverDomains;
if (isExcludedDomain) {
return false;
}
const serverConfig = await firstValueFrom(this.configService.serverConfig$);
const isOriginEqualBitwardenVault = origin === serverConfig.environment?.vault;
if (isOriginEqualBitwardenVault) {
return false;
}
return (
userEnabledPasskeys && isUserLoggedIn && !isExcludedDomain && !isOriginEqualBitwardenVault
);
return await firstValueFrom(this.vaultSettingsService.enablePasskeys$);
}
async createCredential(
@@ -70,6 +76,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
abortController = new AbortController(),
): Promise<CreateCredentialResult> {
const parsedOrigin = parse(params.origin, { allowPrivateDomains: true });
const enableFido2VaultCredentials = await this.isFido2FeatureEnabled(
parsedOrigin.hostname,
params.origin,
@@ -346,7 +353,7 @@ function setAbortTimeout(
);
}
return window.setTimeout(() => abortController.abort(), clampedTimeout);
return self.setTimeout(() => abortController.abort(), clampedTimeout);
}
/**

View File

@@ -0,0 +1,40 @@
import { Fido2Utils } from "./fido2-utils";
describe("Fido2 Utils", () => {
const asciiHelloWorldArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100];
const b64HelloWorldString = "aGVsbG8gd29ybGQ=";
describe("fromBufferToB64(...)", () => {
it("should convert an ArrayBuffer to a b64 string", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;
const b64String = Fido2Utils.fromBufferToB64(buffer);
expect(b64String).toBe(b64HelloWorldString);
});
it("should return an empty string when given an empty ArrayBuffer", () => {
const buffer = new Uint8Array([]).buffer;
const b64String = Fido2Utils.fromBufferToB64(buffer);
expect(b64String).toBe("");
});
it("should return null when given null input", () => {
const b64String = Fido2Utils.fromBufferToB64(null);
expect(b64String).toBeNull();
});
});
describe("fromB64ToArray(...)", () => {
it("should convert a b64 string to an Uint8Array", () => {
const expectedArray = new Uint8Array(asciiHelloWorldArray);
const resultArray = Fido2Utils.fromB64ToArray(b64HelloWorldString);
expect(resultArray).toEqual(expectedArray);
});
it("should return null when given null input", () => {
const expectedArray = Fido2Utils.fromB64ToArray(null);
expect(expectedArray).toBeNull();
});
});
});

View File

@@ -1,14 +1,20 @@
import { Utils } from "../../../platform/misc/utils";
export class Fido2Utils {
static bufferToString(bufferSource: BufferSource): string {
const buffer = Fido2Utils.bufferSourceToUint8Array(bufferSource);
let buffer: Uint8Array;
if (bufferSource instanceof ArrayBuffer || bufferSource.buffer === undefined) {
buffer = new Uint8Array(bufferSource as ArrayBuffer);
} else {
buffer = new Uint8Array(bufferSource.buffer);
}
return Utils.fromBufferToUrlB64(buffer);
return Fido2Utils.fromBufferToB64(buffer)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
static stringToBuffer(str: string): Uint8Array {
return Utils.fromUrlB64ToArray(str);
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str));
}
static bufferSourceToUint8Array(bufferSource: BufferSource) {
@@ -23,4 +29,52 @@ export class Fido2Utils {
private static isArrayBuffer(bufferSource: BufferSource): bufferSource is ArrayBuffer {
return bufferSource instanceof ArrayBuffer || bufferSource.buffer === undefined;
}
static fromB64toUrlB64(b64Str: string) {
return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
static fromBufferToB64(buffer: ArrayBuffer): string {
if (buffer == null) {
return null;
}
let binary = "";
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return globalThis.btoa(binary);
}
static fromB64ToArray(str: string): Uint8Array {
if (str == null) {
return null;
}
const binaryString = globalThis.atob(str);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
static fromUrlB64ToB64(urlB64Str: string): string {
let output = urlB64Str.replace(/-/g, "+").replace(/_/g, "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw new Error("Illegal base64url string!");
}
return output;
}
}