1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

update tests and cleanup

This commit is contained in:
Jonathan Prusik
2024-12-16 11:58:35 -05:00
parent d62edcffa5
commit c339d684f8
13 changed files with 234 additions and 100 deletions

View File

@@ -15,7 +15,6 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import {
ButtonModule,
@@ -26,6 +25,7 @@ import {
LinkModule,
SectionComponent,
SectionHeaderComponent,
ToastService,
TypographyModule,
} from "@bitwarden/components";
@@ -59,7 +59,8 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
],
})
export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
@ViewChildren("uriInput") uriInputElements: QueryList<ElementRef<HTMLInputElement>>;
@ViewChildren("uriInput") uriInputElements: QueryList<ElementRef<HTMLInputElement>> =
new QueryList();
dataIsPristine = true;
isLoading = false;
@@ -73,7 +74,7 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
constructor(
private domainSettingsService: DomainSettingsService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private toastService: ToastService,
) {}
async ngAfterViewInit() {
@@ -150,11 +151,11 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
const validatedHost = Utils.getHostname(uri);
if (!validatedHost) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("excludedDomainsInvalidDomain", uri),
);
this.toastService.showToast({
message: this.i18nService.t("excludedDomainsInvalidDomain", uri),
title: "",
variant: "error",
});
// Don't reset via `handleStateUpdate` to allow existing input value correction
this.isLoading = false;
@@ -176,7 +177,7 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
if (stateIsUnchanged) {
// Reset UI state directly
const constructedNeverDomainsState = this.storedBlockedDomains.reduce(
(neverDomains, uri) => ({ ...neverDomains, [uri]: null }),
(neverDomains: NeverDomains, uri: string) => ({ ...neverDomains, [uri]: null }),
{},
);
this.handleStateUpdate(constructedNeverDomainsState);
@@ -184,13 +185,17 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
await this.domainSettingsService.setBlockedInteractionsUris(newBlockedDomainsSaveState);
}
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("blockedDomainsSavedSuccess"),
);
this.toastService.showToast({
message: this.i18nService.t("blockedDomainsSavedSuccess"),
title: "",
variant: "success",
});
} catch {
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
this.toastService.showToast({
message: this.i18nService.t("unexpectedError"),
title: "",
variant: "error",
});
// Don't reset via `handleStateUpdate` to preserve input values
this.isLoading = false;

View File

@@ -1,5 +1,3 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import {
QueryList,
@@ -17,7 +15,6 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import {
ButtonModule,
@@ -28,6 +25,7 @@ import {
LinkModule,
SectionComponent,
SectionHeaderComponent,
ToastService,
TypographyModule,
} from "@bitwarden/components";
@@ -62,7 +60,8 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
],
})
export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy {
@ViewChildren("uriInput") uriInputElements: QueryList<ElementRef<HTMLInputElement>>;
@ViewChildren("uriInput") uriInputElements: QueryList<ElementRef<HTMLInputElement>> =
new QueryList();
accountSwitcherEnabled = false;
dataIsPristine = true;
@@ -77,7 +76,7 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy {
constructor(
private domainSettingsService: DomainSettingsService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private toastService: ToastService,
) {
this.accountSwitcherEnabled = enableAccountSwitching();
}
@@ -156,11 +155,11 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy {
const validatedHost = Utils.getHostname(uri);
if (!validatedHost) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("excludedDomainsInvalidDomain", uri),
);
this.toastService.showToast({
message: this.i18nService.t("excludedDomainsInvalidDomain", uri),
title: "",
variant: "error",
});
// Don't reset via `handleStateUpdate` to allow existing input value correction
this.isLoading = false;
@@ -182,7 +181,7 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy {
if (stateIsUnchanged) {
// Reset UI state directly
const constructedNeverDomainsState = this.storedExcludedDomains.reduce(
(neverDomains, uri) => ({ ...neverDomains, [uri]: null }),
(neverDomains: NeverDomains, uri: string) => ({ ...neverDomains, [uri]: null }),
{},
);
this.handleStateUpdate(constructedNeverDomainsState);
@@ -190,13 +189,17 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy {
await this.domainSettingsService.setNeverDomains(newExcludedDomainsSaveState);
}
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("excludedDomainsSavedSuccess"),
);
this.toastService.showToast({
message: this.i18nService.t("excludedDomainsSavedSuccess"),
title: "",
variant: "success",
});
} catch {
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
this.toastService.showToast({
message: this.i18nService.t("unexpectedError"),
title: "",
variant: "error",
});
// Don't reset via `handleStateUpdate` to preserve input values
this.isLoading = false;

View File

@@ -98,6 +98,8 @@ describe("AutofillService", () => {
let messageListener: MockProxy<MessageListener>;
beforeEach(() => {
configService = mock<ConfigService>();
configService.getFeatureFlag$.mockImplementation(() => of(false));
scriptInjectorService = new BrowserScriptInjectorService(
domainSettingsService,
platformUtilsService,
@@ -110,10 +112,10 @@ describe("AutofillService", () => {
autofillSettingsService.inlineMenuVisibility$ = inlineMenuVisibilityMock$;
autofillSettingsService.showInlineMenuCards$ = showInlineMenuCardsMock$;
autofillSettingsService.showInlineMenuIdentities$ = showInlineMenuIdentitiesMock$;
autofillSettingsService.autofillOnPageLoad$ = of(true);
activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
authService = mock<AuthService>();
authService.activeAccountStatus$ = activeAccountStatusMock$;
configService = mock<ConfigService>();
messageListener = mock<MessageListener>();
enableChangedPasswordPromptMock$ = new BehaviorSubject(true);
enableAddedLoginPromptMock$ = new BehaviorSubject(true);
@@ -389,6 +391,7 @@ describe("AutofillService", () => {
);
tabMock = createChromeTabMock();
sender = { tab: tabMock, frameId: 1 };
jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock);
jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation();
jest
.spyOn(autofillService, "getInlineMenuVisibility")

View File

@@ -1,9 +1,22 @@
import { mock } from "jest-mock-extended";
import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import {
DomainSettingsService,
DefaultDomainSettingsService,
} from "@bitwarden/common/autofill/services/domain-settings.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import {
FakeStateProvider,
FakeAccountService,
mockAccountServiceWith,
} from "@bitwarden/common/spec";
import { UserId } from "@bitwarden/common/types/guid";
import { createChromeTabMock } from "../../autofill/spec/autofill-mocks";
import { BrowserApi } from "../browser/browser-api";
import {
@@ -12,8 +25,19 @@ import {
} from "./abstractions/script-injector.service";
import { BrowserScriptInjectorService } from "./browser-script-injector.service";
const mockEquivalentDomains = [
["example.com", "exampleapp.com", "example.co.uk", "ejemplo.es"],
["bitwarden.com", "bitwarden.co.uk", "sm-bitwarden.com"],
["example.co.uk", "exampleapp.co.uk"],
];
describe("ScriptInjectorService", () => {
const tabId = 1;
const tabMock = createChromeTabMock({ id: tabId });
const mockBlockedURI = new URL(tabMock.url);
jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation();
jest.spyOn(BrowserApi, "isManifestVersion");
const combinedManifestVersionFile = "content/autofill-init.js";
const mv2SpecificFile = "content/autofill-init-mv2.js";
const mv2Details = { file: mv2SpecificFile };
@@ -23,14 +47,24 @@ describe("ScriptInjectorService", () => {
runAt: "document_start",
};
const manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get");
let scriptInjectorService: BrowserScriptInjectorService;
jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation();
jest.spyOn(BrowserApi, "isManifestVersion");
const domainSettingsService = mock<DomainSettingsService>();
const platformUtilsService = mock<PlatformUtilsService>();
const logService = mock<LogService>();
const platformUtilsService = mock<PlatformUtilsService>();
const mockUserId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
const fakeStateProvider: FakeStateProvider = new FakeStateProvider(accountService);
let configService: MockProxy<ConfigService>;
let domainSettingsService: DomainSettingsService;
const expectedBlockedURIError = new Error("This URI of this tab is on the blocked domains list.");
beforeEach(() => {
jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock);
configService = mock<ConfigService>();
configService.getFeatureFlag$.mockImplementation(() => of(false));
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService);
domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains);
domainSettingsService.blockedInteractionsUris$ = of(null);
scriptInjectorService = new BrowserScriptInjectorService(
domainSettingsService,
platformUtilsService,
@@ -77,6 +111,76 @@ describe("ScriptInjectorService", () => {
{ world: "ISOLATED" },
);
});
it("skips injecting the script in manifest v3 when the tab domain is a blocked domain", async () => {
domainSettingsService.blockedInteractionsUris$ = of({ [mockBlockedURI.host]: null });
manifestVersionSpy.mockReturnValue(3);
await expect(
scriptInjectorService.inject({
tabId,
injectDetails: {
file: combinedManifestVersionFile,
frame: 10,
...sharedInjectDetails,
},
}),
).rejects.toThrow(expectedBlockedURIError);
});
it("skips injecting the script in manifest v2 when the tab domain is a blocked domain", async () => {
domainSettingsService.blockedInteractionsUris$ = of({ [mockBlockedURI.host]: null });
manifestVersionSpy.mockReturnValue(2);
await expect(
scriptInjectorService.inject({
tabId,
injectDetails: {
file: combinedManifestVersionFile,
frame: "all_frames",
...sharedInjectDetails,
},
}),
).rejects.toThrow(expectedBlockedURIError);
});
it("injects the script in manifest v2 when given combined injection details", async () => {
manifestVersionSpy.mockReturnValue(2);
await scriptInjectorService.inject({
tabId,
injectDetails: {
file: combinedManifestVersionFile,
frame: "all_frames",
...sharedInjectDetails,
},
});
expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(tabId, {
...sharedInjectDetails,
allFrames: true,
file: combinedManifestVersionFile,
});
});
it("injects the script in manifest v3 when given combined injection details", async () => {
manifestVersionSpy.mockReturnValue(3);
await scriptInjectorService.inject({
tabId,
injectDetails: {
file: combinedManifestVersionFile,
frame: 10,
...sharedInjectDetails,
},
});
expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(
tabId,
{ ...sharedInjectDetails, frameId: 10, file: combinedManifestVersionFile },
{ world: "ISOLATED" },
);
});
});
describe("injection of mv2 specific details", () => {

View File

@@ -1,7 +1,6 @@
import { Subject, takeUntil } from "rxjs";
import { firstValueFrom } from "rxjs";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -18,22 +17,12 @@ import {
export class BrowserScriptInjectorService extends ScriptInjectorService {
blockedDomains: Set<string> = null;
private destroy$ = new Subject<void>();
constructor(
private readonly domainSettingsService: DomainSettingsService,
private readonly platformUtilsService: PlatformUtilsService,
private readonly logService: LogService,
) {
super();
this.domainSettingsService.blockedInteractionsUris$
.pipe(takeUntil(this.destroy$))
.subscribe((neverDomains: NeverDomains) => {
if (neverDomains) {
this.blockedDomains = new Set(Object.keys(neverDomains));
}
});
}
/**
@@ -49,10 +38,20 @@ export class BrowserScriptInjectorService extends ScriptInjectorService {
throw new Error("No file specified for script injection");
}
const tab = tabId && (await BrowserApi.getTab(tabId));
const tabURL = tab?.url ? new URL(tab.url) : null;
// Check if the tab URI is on the disabled URIs list
const tab = await BrowserApi.getTab(tabId);
const tabURL = tab.url ? new URL(tab.url) : null;
const injectionAllowedInTab = !(tabURL && this.blockedDomains?.has(tabURL.hostname));
let injectionAllowedInTab = true;
const blockedDomains = await firstValueFrom(
this.domainSettingsService.blockedInteractionsUris$,
);
if (blockedDomains && tabURL?.hostname) {
const blockedDomainsSet = new Set(Object.keys(blockedDomains));
injectionAllowedInTab = !(tabURL && blockedDomainsSet.has(tabURL.hostname));
}
if (!injectionAllowedInTab) {
throw new Error("This URI of this tab is on the blocked domains list.");

View File

@@ -1,5 +1,5 @@
import { mock } from "jest-mock-extended";
import { firstValueFrom } from "rxjs";
import { firstValueFrom, of } from "rxjs";
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
@@ -45,8 +45,10 @@ describe("FilelessImporterBackground ", () => {
const platformUtilsService = mock<PlatformUtilsService>();
const logService = mock<LogService>();
let scriptInjectorService: BrowserScriptInjectorService;
let tabMock: chrome.tabs.Tab;
beforeEach(() => {
domainSettingsService.blockedInteractionsUris$ = of(null);
scriptInjectorService = new BrowserScriptInjectorService(
domainSettingsService,
platformUtilsService,
@@ -81,12 +83,13 @@ describe("FilelessImporterBackground ", () => {
beforeEach(() => {
lpImporterPort = createPortSpyMock(FilelessImportPort.LpImporter);
tabMock = lpImporterPort.sender.tab;
jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock);
manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get");
executeScriptInTabSpy = jest.spyOn(BrowserApi, "executeScriptInTab").mockResolvedValue(null);
jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Unlocked);
jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(true);
jest.spyOn(filelessImporterBackground as any, "removeIndividualVault");
(firstValueFrom as jest.Mock).mockResolvedValue(false);
});
it("ignores the port connection if the port name is not present in the set of filelessImportNames", async () => {
@@ -99,6 +102,7 @@ describe("FilelessImporterBackground ", () => {
});
it("posts a message to the port indicating that the fileless import feature is disabled if the user's auth status is not unlocked", async () => {
(firstValueFrom as jest.Mock).mockResolvedValue(false);
jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Locked);
triggerRuntimeOnConnectEvent(lpImporterPort);
@@ -135,6 +139,7 @@ describe("FilelessImporterBackground ", () => {
});
it("posts a message to the port indicating that the fileless import feature is enabled", async () => {
(firstValueFrom as jest.Mock).mockResolvedValue(false);
triggerRuntimeOnConnectEvent(lpImporterPort);
await flushPromises();
@@ -158,6 +163,7 @@ describe("FilelessImporterBackground ", () => {
});
it("triggers an injection of the `lp-suppress-import-download-script-append-mv2.js` script in manifest v2", async () => {
(firstValueFrom as jest.Mock).mockResolvedValueOnce(false);
manifestVersionSpy.mockReturnValue(2);
triggerRuntimeOnConnectEvent(lpImporterPort);

View File

@@ -44,7 +44,7 @@ export class AutofillVaultListItemsComponent implements OnInit {
/**
* Indicators for the section.
*/
@Input() sectionIndicators: string[];
@Input() sectionIndicators: string[] = [];
/**
* Observable that determines whether the empty autofill tip should be shown.

View File

@@ -103,7 +103,7 @@ export class VaultListItemsContainerComponent implements AfterViewInit {
/**
* Indicators for the section.
*/
@Input() sectionIndicators: string[];
@Input() sectionIndicators: string[] = [];
/**
* Optional description for the vault list item section. Will be shown below the title even when

View File

@@ -62,7 +62,7 @@ export class VaultV2Component implements OnInit, OnDestroy {
protected loading$ = this.vaultPopupItemsService.loading$;
protected scriptInjectionIsBlocked = false;
protected showScriptInjectionIsBlockedBanner = false;
protected autofillTabHostname: string = null;
protected autofillTabHostname: string | null = null;
protected sectionIndicators: string[] = [];
protected newItemItemValues$: Observable<NewItemInitialValues> =
@@ -151,20 +151,24 @@ export class VaultV2Component implements OnInit, OnDestroy {
ngOnDestroy(): void {}
handleScriptInjectionIsBlockedBannerDismiss() {
firstValueFrom(this.domainSettingsService.blockedInteractionsUris$)
.then((blockedURIs) => {
if (!this.autofillTabHostname) {
return;
}
try {
void firstValueFrom(this.domainSettingsService.blockedInteractionsUris$).then(
(blockedURIs) => {
this.showScriptInjectionIsBlockedBanner = false;
this.domainSettingsService
.setBlockedInteractionsUris({
void this.domainSettingsService.setBlockedInteractionsUris({
...blockedURIs,
[this.autofillTabHostname]: { bannerIsDismissed: true },
})
.catch(() => {
/* no-op */
});
})
.catch(() => {
/* no-op */
[this.autofillTabHostname as string]: { bannerIsDismissed: true },
});
},
);
} catch (e) {
throw new Error(
"There was a problem dismissing the blocked interaction URI notification banner",
);
}
}
}

View File

@@ -483,7 +483,29 @@ export class ServiceContainer {
this.containerService = new ContainerService(this.keyService, this.encryptService);
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
this.configApiService = new ConfigApiService(this.apiService, this.tokenService);
this.authService = new AuthService(
this.accountService,
this.messagingService,
this.keyService,
this.apiService,
this.stateService,
this.tokenService,
);
this.configService = new DefaultConfigService(
this.configApiService,
this.environmentService,
this.logService,
this.stateProvider,
this.authService,
);
this.domainSettingsService = new DefaultDomainSettingsService(
this.stateProvider,
this.configService,
);
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
@@ -579,25 +601,6 @@ export class ServiceContainer {
this.taskSchedulerService = new DefaultTaskSchedulerService(this.logService);
this.authService = new AuthService(
this.accountService,
this.messagingService,
this.keyService,
this.apiService,
this.stateService,
this.tokenService,
);
this.configApiService = new ConfigApiService(this.apiService, this.tokenService);
this.configService = new DefaultConfigService(
this.configApiService,
this.environmentService,
this.logService,
this.stateProvider,
this.authService,
);
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
this.deviceTrustService = new DeviceTrustService(
this.keyGenerationService,

View File

@@ -463,6 +463,11 @@ const safeProviders: SafeProvider[] = [
useClass: CipherFileUploadService,
deps: [ApiServiceAbstraction, FileUploadServiceAbstraction],
}),
safeProvider({
provide: DomainSettingsService,
useClass: DefaultDomainSettingsService,
deps: [StateProvider, ConfigService],
}),
safeProvider({
provide: CipherServiceAbstraction,
useFactory: (
@@ -1243,11 +1248,6 @@ const safeProviders: SafeProvider[] = [
useClass: BadgeSettingsService,
deps: [StateProvider],
}),
safeProvider({
provide: DomainSettingsService,
useClass: DefaultDomainSettingsService,
deps: [StateProvider, ConfigService],
}),
safeProvider({
provide: BiometricStateService,
useClass: DefaultBiometricStateService,

View File

@@ -1,5 +1,8 @@
import { MockProxy, mock } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { FakeStateProvider, FakeAccountService, mockAccountServiceWith } from "../../../spec";
import { Utils } from "../../platform/misc/utils";
import { UserId } from "../../types/guid";
@@ -8,8 +11,10 @@ import { DefaultDomainSettingsService, DomainSettingsService } from "./domain-se
describe("DefaultDomainSettingsService", () => {
let domainSettingsService: DomainSettingsService;
const configServiceMock = mock<ConfigService>();
const mockUserId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
let mockConfigService: MockProxy<ConfigService>;
const fakeStateProvider: FakeStateProvider = new FakeStateProvider(accountService);
const mockEquivalentDomains = [
@@ -19,10 +24,12 @@ describe("DefaultDomainSettingsService", () => {
];
beforeEach(() => {
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, mockConfigService);
jest.spyOn(configServiceMock, "getFeatureFlag$").mockReturnValue(of(false));
jest.spyOn(domainSettingsService, "getUrlEquivalentDomains");
domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains);
domainSettingsService.blockedInteractionsUris$ = of(null);
});
describe("getUrlEquivalentDomains", () => {

View File

@@ -3,7 +3,6 @@
import { combineLatest, map, Observable } from "rxjs";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import {
NeverDomains,
@@ -11,6 +10,7 @@ import {
UriMatchStrategySetting,
UriMatchStrategy,
} from "../../models/domain/domain-service";
import { ConfigService } from "../../platform/abstractions/config/config.service";
import { Utils } from "../../platform/misc/utils";
import {
DOMAIN_SETTINGS_DISK,
@@ -99,7 +99,7 @@ export class DefaultDomainSettingsService implements DomainSettingsService {
this.blockedInteractionsUris$ = combineLatest([
this.blockedInteractionsUrisState.state$,
this.configService.getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain),
this.configService?.getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain),
]).pipe(
map(([blockedUris, blockBrowserInjectionsByDomainEnabled]) => {
if (!blockBrowserInjectionsByDomainEnabled) {