diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index f0da1af11d4..ebad626d8df 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -8,11 +8,21 @@ import { AutofillOverlayVisibility, } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { + DefaultDomainSettingsService, + DomainSettingsService, +} from "@bitwarden/common/autofill/services/domain-settings.service"; import { ThemeType } from "@bitwarden/common/platform/enums"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service"; import { I18nService } from "@bitwarden/common/platform/services/i18n.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; -import { SettingsService } from "@bitwarden/common/services/settings.service"; +import { + FakeStateProvider, + FakeAccountService, + mockAccountServiceWith, +} from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; import { 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"; @@ -41,6 +51,10 @@ import OverlayBackground from "./overlay.background"; const iconServerUrl = "https://icons.bitwarden.com/"; describe("OverlayBackground", () => { + const mockUserId = Utils.newGuid() as UserId; + const accountService: FakeAccountService = mockAccountServiceWith(mockUserId); + const fakeStateProvider: FakeStateProvider = new FakeStateProvider(accountService); + let domainSettingsService: DomainSettingsService; let buttonPortSpy: chrome.runtime.Port; let listPortSpy: chrome.runtime.Port; let overlayBackground: OverlayBackground; @@ -50,7 +64,6 @@ describe("OverlayBackground", () => { const environmentService = mock({ getIconsUrl: () => iconServerUrl, }); - const settingsService = mock(); const stateService = mock(); const autofillSettingsService = mock(); const i18nService = mock(); @@ -72,12 +85,13 @@ describe("OverlayBackground", () => { }; beforeEach(() => { + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); overlayBackground = new OverlayBackground( cipherService, autofillService, authService, environmentService, - settingsService, + domainSettingsService, stateService, autofillSettingsService, i18nService, @@ -90,6 +104,7 @@ describe("OverlayBackground", () => { .mockResolvedValue(AutofillOverlayVisibility.OnFieldFocus); themeStateService.selectedTheme$ = of(ThemeType.Light); + domainSettingsService.showFavicons$ = of(true); void overlayBackground.init(); }); @@ -274,7 +289,7 @@ describe("OverlayBackground", () => { card: { subTitle: "Mastercard, *1234" }, }); - it("formats and returns the cipher data", () => { + it("formats and returns the cipher data", async () => { overlayBackground["overlayLoginCiphers"] = new Map([ ["overlay-cipher-0", cipher2], ["overlay-cipher-1", cipher1], @@ -282,7 +297,7 @@ describe("OverlayBackground", () => { ["overlay-cipher-3", cipher4], ]); - const overlayCipherData = overlayBackground["getOverlayCipherData"](); + const overlayCipherData = await overlayBackground["getOverlayCipherData"](); expect(overlayCipherData).toStrictEqual([ { diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 00be50c3284..6c3aea9dc71 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -1,10 +1,10 @@ import { firstValueFrom } from "rxjs"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { SHOW_AUTOFILL_BUTTON } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -92,7 +92,7 @@ class OverlayBackground implements OverlayBackgroundInterface { private autofillService: AutofillService, private authService: AuthService, private environmentService: EnvironmentService, - private settingsService: SettingsService, + private domainSettingsService: DomainSettingsService, private stateService: StateService, private autofillSettingsService: AutofillSettingsServiceAbstraction, private i18nService: I18nService, @@ -145,7 +145,7 @@ class OverlayBackground implements OverlayBackgroundInterface { this.overlayLoginCiphers.set(`overlay-cipher-${cipherIndex}`, ciphersViews[cipherIndex]); } - const ciphers = this.getOverlayCipherData(); + const ciphers = await this.getOverlayCipherData(); this.overlayListPort?.postMessage({ command: "updateOverlayListCiphers", ciphers }); await BrowserApi.tabSendMessageData(currentTab, "updateIsOverlayCiphersPopulated", { isOverlayCiphersPopulated: Boolean(ciphers.length), @@ -156,8 +156,8 @@ class OverlayBackground implements OverlayBackgroundInterface { * Strips out unnecessary data from the ciphers and returns an array of * objects that contain the cipher data needed for the overlay list. */ - private getOverlayCipherData(): OverlayCipherData[] { - const isFaviconDisabled = this.settingsService.getDisableFavicon(); + private async getOverlayCipherData(): Promise { + const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$); const overlayCiphersArray = Array.from(this.overlayLoginCiphers); const overlayCipherData = []; let loginCipherIcon: WebsiteIconData; @@ -165,7 +165,7 @@ class OverlayBackground implements OverlayBackgroundInterface { for (let cipherIndex = 0; cipherIndex < overlayCiphersArray.length; cipherIndex++) { const [overlayCipherId, cipher] = overlayCiphersArray[cipherIndex]; if (!loginCipherIcon && cipher.type === CipherType.Login) { - loginCipherIcon = buildCipherIcon(this.iconsServerUrl, cipher, isFaviconDisabled); + loginCipherIcon = buildCipherIcon(this.iconsServerUrl, cipher, showFavicons); } overlayCipherData.push({ @@ -177,7 +177,7 @@ class OverlayBackground implements OverlayBackgroundInterface { icon: cipher.type === CipherType.Login ? loginCipherIcon - : buildCipherIcon(this.iconsServerUrl, cipher, isFaviconDisabled), + : buildCipherIcon(this.iconsServerUrl, cipher, showFavicons), login: cipher.type === CipherType.Login ? { username: cipher.login.username } : null, card: cipher.type === CipherType.Card ? cipher.card.subTitle : null, }); @@ -699,7 +699,7 @@ class OverlayBackground implements OverlayBackgroundInterface { styleSheetUrl: chrome.runtime.getURL(`overlay/${isOverlayListPort ? "list" : "button"}.css`), theme: await firstValueFrom(this.themeStateService.selectedTheme$), translations: this.getTranslations(), - ciphers: isOverlayListPort ? this.getOverlayCipherData() : null, + ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null, }); this.updateOverlayPosition({ overlayElement: isOverlayListPort diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index b0f65ec8ce3..b3b9be3dcd4 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -14,7 +14,6 @@ import { EventCollectionService as EventCollectionServiceAbstraction } from "@bi import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; -import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; @@ -213,7 +212,6 @@ import { BrowserPlatformUtilsService } from "../platform/services/platform-utils import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider"; import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service"; import { BrowserSendService } from "../services/browser-send.service"; -import { BrowserSettingsService } from "../services/browser-settings.service"; import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service"; import FilelessImporterBackground from "../tools/background/fileless-importer.background"; import { BrowserFido2UserInterfaceService } from "../vault/fido2/browser-fido2-user-interface.service"; @@ -242,7 +240,6 @@ export default class MainBackground { appIdService: AppIdServiceAbstraction; apiService: ApiServiceAbstraction; environmentService: BrowserEnvironmentService; - settingsService: SettingsServiceAbstraction; cipherService: CipherServiceAbstraction; folderService: InternalFolderServiceAbstraction; collectionService: CollectionServiceAbstraction; @@ -488,7 +485,6 @@ export default class MainBackground { (expired: boolean) => this.logout(expired), ); this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); - this.settingsService = new BrowserSettingsService(this.stateService); this.fileUploadService = new FileUploadService(this.logService); this.cipherFileUploadService = new CipherFileUploadService( this.apiService, @@ -890,7 +886,7 @@ export default class MainBackground { this.autofillService, this.authService, this.environmentService, - this.settingsService, + this.domainSettingsService, this.stateService, this.autofillSettingsService, this.i18nService, diff --git a/apps/browser/src/background/service-factories/settings-service.factory.ts b/apps/browser/src/background/service-factories/settings-service.factory.ts deleted file mode 100644 index 28e97de51fa..00000000000 --- a/apps/browser/src/background/service-factories/settings-service.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SettingsService as AbstractSettingsService } from "@bitwarden/common/abstractions/settings.service"; - -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../platform/background/service-factories/state-service.factory"; -import { BrowserSettingsService } from "../../services/browser-settings.service"; - -type SettingsServiceFactoryOptions = FactoryOptions; - -export type SettingsServiceInitOptions = SettingsServiceFactoryOptions & StateServiceInitOptions; - -export function settingsServiceFactory( - cache: { settingsService?: AbstractSettingsService } & CachedServices, - opts: SettingsServiceInitOptions, -): Promise { - return factory( - cache, - "settingsService", - opts, - async () => new BrowserSettingsService(await stateServiceFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 3fa03804ba4..52de0303fae 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -19,7 +19,6 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; @@ -40,6 +39,10 @@ import { AutofillSettingsService, AutofillSettingsServiceAbstraction, } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { + DefaultDomainSettingsService, + DomainSettingsService, +} from "@bitwarden/common/autofill/services/domain-settings.service"; import { UserNotificationSettingsService, UserNotificationSettingsServiceAbstraction, @@ -115,7 +118,6 @@ import { ForegroundPlatformUtilsService } from "../../platform/services/platform import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; import { BrowserSendService } from "../../services/browser-send.service"; -import { BrowserSettingsService } from "../../services/browser-settings.service"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; import { VaultFilterService } from "../../vault/services/vault-filter.service"; @@ -334,11 +336,9 @@ function getBgService(service: keyof MainBackground) { }, { provide: SyncService, useFactory: getBgService("syncService"), deps: [] }, { - provide: SettingsService, - useFactory: (stateService: StateServiceAbstraction) => { - return new BrowserSettingsService(stateService); - }, - deps: [StateServiceAbstraction], + provide: DomainSettingsService, + useClass: DefaultDomainSettingsService, + deps: [StateProvider], }, { provide: AbstractStorageService, diff --git a/apps/browser/src/popup/settings/options.component.ts b/apps/browser/src/popup/settings/options.component.ts index 2142693e2a4..dbdb94c5860 100644 --- a/apps/browser/src/popup/settings/options.component.ts +++ b/apps/browser/src/popup/settings/options.component.ts @@ -1,7 +1,6 @@ import { Component, OnInit } from "@angular/core"; import { firstValueFrom } from "rxjs"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; @@ -56,7 +55,6 @@ export class OptionsComponent implements OnInit { private badgeSettingsService: BadgeSettingsServiceAbstraction, i18nService: I18nService, private themeStateService: ThemeStateService, - private settingsService: SettingsService, private vaultSettingsService: VaultSettingsService, ) { this.themeOptions = [ @@ -119,7 +117,7 @@ export class OptionsComponent implements OnInit { this.enableAutoTotpCopy = await firstValueFrom(this.autofillSettingsService.autoCopyTotp$); - this.enableFavicon = !this.settingsService.getDisableFavicon(); + this.enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$); this.enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$); @@ -169,7 +167,7 @@ export class OptionsComponent implements OnInit { } async updateFavicon() { - await this.settingsService.setDisableFavicon(!this.enableFavicon); + await this.domainSettingsService.setShowFavicons(this.enableFavicon); } async updateBadgeCounter() { diff --git a/apps/browser/src/services/browser-settings.service.ts b/apps/browser/src/services/browser-settings.service.ts deleted file mode 100644 index 50c27ce4f69..00000000000 --- a/apps/browser/src/services/browser-settings.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BehaviorSubject } from "rxjs"; - -import { SettingsService } from "@bitwarden/common/services/settings.service"; - -import { browserSession, sessionSync } from "../platform/decorators/session-sync-observable"; - -@browserSession -export class BrowserSettingsService extends SettingsService { - @sessionSync({ initializer: (b: boolean) => b }) - protected _disableFavicon: BehaviorSubject; -} diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 7435020af03..95e306bfc0e 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -90,7 +90,6 @@ import { AuditService } from "@bitwarden/common/services/audit.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { SearchService } from "@bitwarden/common/services/search.service"; -import { SettingsService } from "@bitwarden/common/services/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; import { @@ -159,7 +158,6 @@ export class Main { appIdService: AppIdService; apiService: NodeApiService; environmentService: EnvironmentService; - settingsService: SettingsService; cipherService: CipherService; folderService: InternalFolderService; organizationUserService: OrganizationUserService; @@ -375,7 +373,6 @@ export class Main { this.containerService = new ContainerService(this.cryptoService, this.encryptService); - this.settingsService = new SettingsService(this.stateService); this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); this.fileUploadService = new FileUploadService(this.logService); diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index 242e1533e96..e066d4ec2e2 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -3,13 +3,12 @@ import { FormBuilder } from "@angular/forms"; import { BehaviorSubject, firstValueFrom, Observable, Subject } from "rxjs"; import { concatMap, debounceTime, filter, map, switchMap, takeUntil, tap } from "rxjs/operators"; -import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { DeviceType } from "@bitwarden/common/enums"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -115,9 +114,8 @@ export class SettingsComponent implements OnInit { private autofillSettingsService: AutofillSettingsServiceAbstraction, private messagingService: MessagingService, private cryptoService: CryptoService, - private modalService: ModalService, private themeStateService: ThemeStateService, - private settingsService: SettingsService, + private domainSettingsService: DomainSettingsService, private dialogService: DialogService, private userVerificationService: UserVerificationServiceAbstraction, private biometricStateService: BiometricStateService, @@ -251,7 +249,7 @@ export class SettingsComponent implements OnInit { approveLoginRequests: (await this.stateService.getApproveLoginRequests()) ?? false, clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$), minimizeOnCopyToClipboard: await this.stateService.getMinimizeOnCopyToClipboard(), - enableFavicons: !(await this.stateService.getDisableFavicon()), + enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$), enableTray: await this.stateService.getEnableTray(), enableMinToTray: await this.stateService.getEnableMinimizeToTray(), enableCloseToTray: await this.stateService.getEnableCloseToTray(), @@ -498,7 +496,7 @@ export class SettingsComponent implements OnInit { } async saveFavicons() { - await this.settingsService.setDisableFavicon(!this.form.value.enableFavicons); + await this.domainSettingsService.setShowFavicons(this.form.value.enableFavicons); this.messagingService.send("refreshCiphers"); } diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index c674915b325..fa396ab313b 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -19,7 +19,6 @@ import { FingerprintDialogComponent } from "@bitwarden/auth/angular"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; @@ -123,7 +122,6 @@ export class AppComponent implements OnInit, OnDestroy { constructor( private broadcasterService: BroadcasterService, private folderService: InternalFolderService, - private settingsService: SettingsService, private syncService: SyncService, private passwordGenerationService: PasswordGenerationServiceAbstraction, private cipherService: CipherService, diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index 9d6ff91666c..a1b74566279 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -9,7 +9,6 @@ import { Subject, switchMap, takeUntil, timer } from "rxjs"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -44,7 +43,6 @@ import { SingleOrgPolicy, TwoFactorAuthenticationPolicy, } from "./admin-console/organizations/policies"; -import { RouterService } from "./core"; const BroadcasterSubscriptionId = "AppComponent"; const IdleTimeout = 60000 * 10; // 10 minutes @@ -65,7 +63,6 @@ export class AppComponent implements OnDestroy, OnInit { @Inject(DOCUMENT) private document: Document, private broadcasterService: BroadcasterService, private folderService: InternalFolderService, - private settingsService: SettingsService, private syncService: SyncService, private passwordGenerationService: PasswordGenerationServiceAbstraction, private cipherService: CipherService, @@ -81,7 +78,6 @@ export class AppComponent implements OnDestroy, OnInit { private sanitizer: DomSanitizer, private searchService: SearchService, private notificationsService: NotificationsService, - private routerService: RouterService, private stateService: StateService, private eventUploadService: EventUploadService, private policyService: InternalPolicyService, diff --git a/apps/web/src/app/settings/preferences.component.ts b/apps/web/src/app/settings/preferences.component.ts index aa2bc22beac..7f9eabb6b3b 100644 --- a/apps/web/src/app/settings/preferences.component.ts +++ b/apps/web/src/app/settings/preferences.component.ts @@ -2,13 +2,12 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder } from "@angular/forms"; import { concatMap, filter, firstValueFrom, map, Observable, Subject, takeUntil, tap } from "rxjs"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ThemeType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -50,9 +49,8 @@ export class PreferencesComponent implements OnInit { private i18nService: I18nService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService, private platformUtilsService: PlatformUtilsService, - private messagingService: MessagingService, private themeStateService: ThemeStateService, - private settingsService: SettingsService, + private domainSettingsService: DomainSettingsService, private dialogService: DialogService, ) { this.vaultTimeoutOptions = [ @@ -137,7 +135,7 @@ export class PreferencesComponent implements OnInit { vaultTimeoutAction: await firstValueFrom( this.vaultTimeoutSettingsService.vaultTimeoutAction$(), ), - enableFavicons: !(await this.settingsService.getDisableFavicon()), + enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$), theme: await firstValueFrom(this.themeStateService.selectedTheme$), locale: (await firstValueFrom(this.i18nService.userSetLocale$)) ?? null, }; @@ -160,7 +158,7 @@ export class PreferencesComponent implements OnInit { values.vaultTimeout, values.vaultTimeoutAction, ); - await this.settingsService.setDisableFavicon(!values.enableFavicons); + await this.domainSettingsService.setShowFavicons(values.enableFavicons); await this.themeStateService.setSelectedTheme(values.theme); await this.i18nService.setLocale(values.locale); if (values.locale !== this.startingLocale) { diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts index 8f33c501646..05659de073c 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts @@ -3,11 +3,11 @@ import { RouterModule } from "@angular/router"; import { applicationConfig, Meta, moduleMetadata, Story } from "@storybook/angular"; import { BehaviorSubject, of } from "rxjs"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { OrganizationUserType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @@ -57,19 +57,19 @@ export default { useValue: { activeAccount$: new BehaviorSubject("1").asObservable(), accounts$: new BehaviorSubject({ "1": { profile: { name: "Foo" } } }).asObservable(), - async getDisableFavicon() { - return false; + async getShowFavicon() { + return true; }, } as Partial, }, { - provide: SettingsService, + provide: DomainSettingsService, useValue: { - disableFavicon$: new BehaviorSubject(false).asObservable(), - getDisableFavicon() { - return false; + showFavicons$: new BehaviorSubject(true).asObservable(), + getShowFavicon() { + return true; }, - } as Partial, + } as Partial, }, { provide: AvatarService, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index d8dcf08835e..a509897fd3a 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -15,7 +15,6 @@ import { EventCollectionService as EventCollectionServiceAbstraction } from "@bi import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; -import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; @@ -172,7 +171,6 @@ import { EventCollectionService } from "@bitwarden/common/services/event/event-c import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { SearchService } from "@bitwarden/common/services/search.service"; -import { SettingsService } from "@bitwarden/common/services/settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; import { @@ -583,11 +581,6 @@ const typesafeProviders: Array = [ ], }), safeProvider({ provide: BroadcasterServiceAbstraction, useClass: BroadcasterService, deps: [] }), - safeProvider({ - provide: SettingsServiceAbstraction, - useClass: SettingsService, - deps: [StateServiceAbstraction], - }), safeProvider({ provide: VaultTimeoutSettingsServiceAbstraction, useClass: VaultTimeoutSettingsService, diff --git a/libs/angular/src/vault/components/icon.component.ts b/libs/angular/src/vault/components/icon.component.ts index 33cd2bc71a0..8323c55d4e4 100644 --- a/libs/angular/src/vault/components/icon.component.ts +++ b/libs/angular/src/vault/components/icon.component.ts @@ -8,7 +8,7 @@ import { Observable, } from "rxjs"; -import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { buildCipherIcon } from "@bitwarden/common/vault/icon/build-cipher-icon"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -35,15 +35,15 @@ export class IconComponent implements OnInit { constructor( private environmentService: EnvironmentService, - private settingsService: SettingsService, + private domainSettingsService: DomainSettingsService, ) {} async ngOnInit() { const iconsUrl = this.environmentService.getIconsUrl(); this.data$ = combineLatest([ - this.settingsService.disableFavicon$.pipe(distinctUntilChanged()), + this.domainSettingsService.showFavicons$.pipe(distinctUntilChanged()), this.cipher$.pipe(filter((c) => c !== undefined)), - ]).pipe(map(([disableFavicon, cipher]) => buildCipherIcon(iconsUrl, cipher, disableFavicon))); + ]).pipe(map(([showFavicon, cipher]) => buildCipherIcon(iconsUrl, cipher, showFavicon))); } } diff --git a/libs/common/src/abstractions/settings.service.ts b/libs/common/src/abstractions/settings.service.ts deleted file mode 100644 index e9d8c8b683a..00000000000 --- a/libs/common/src/abstractions/settings.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Observable } from "rxjs"; - -export abstract class SettingsService { - disableFavicon$: Observable; - - setDisableFavicon: (value: boolean) => Promise; - getDisableFavicon: () => boolean; -} diff --git a/libs/common/src/autofill/services/domain-settings.service.ts b/libs/common/src/autofill/services/domain-settings.service.ts index 3131b9c50b5..6ef4d10c0a5 100644 --- a/libs/common/src/autofill/services/domain-settings.service.ts +++ b/libs/common/src/autofill/services/domain-settings.service.ts @@ -16,6 +16,10 @@ import { UserKeyDefinition, } from "../../platform/state"; +const SHOW_FAVICONS = new KeyDefinition(DOMAIN_SETTINGS_DISK, "showFavicons", { + deserializer: (value: boolean) => value ?? true, +}); + const NEVER_DOMAINS = new KeyDefinition(DOMAIN_SETTINGS_DISK, "neverDomains", { deserializer: (value: NeverDomains) => value ?? null, }); @@ -34,6 +38,8 @@ const DEFAULT_URI_MATCH_STRATEGY = new KeyDefinition( ); export abstract class DomainSettingsService { + showFavicons$: Observable; + setShowFavicons: (newValue: boolean) => Promise; neverDomains$: Observable; setNeverDomains: (newValue: NeverDomains) => Promise; equivalentDomains$: Observable; @@ -44,6 +50,9 @@ export abstract class DomainSettingsService { } export class DefaultDomainSettingsService implements DomainSettingsService { + private showFaviconsState: GlobalState; + readonly showFavicons$: Observable; + private neverDomainsState: GlobalState; readonly neverDomains$: Observable; @@ -54,6 +63,9 @@ export class DefaultDomainSettingsService implements DomainSettingsService { readonly defaultUriMatchStrategy$: Observable; constructor(private stateProvider: StateProvider) { + this.showFaviconsState = this.stateProvider.getGlobal(SHOW_FAVICONS); + this.showFavicons$ = this.showFaviconsState.state$.pipe(map((x) => x ?? true)); + this.neverDomainsState = this.stateProvider.getGlobal(NEVER_DOMAINS); this.neverDomains$ = this.neverDomainsState.state$.pipe(map((x) => x ?? null)); @@ -66,6 +78,10 @@ export class DefaultDomainSettingsService implements DomainSettingsService { ); } + async setShowFavicons(newValue: boolean): Promise { + await this.showFaviconsState.update(() => newValue); + } + async setNeverDomains(newValue: NeverDomains): Promise { await this.neverDomainsState.update(() => newValue); } diff --git a/libs/common/src/platform/abstractions/state.service.ts b/libs/common/src/platform/abstractions/state.service.ts index 4c7e38f8e85..3413afe1825 100644 --- a/libs/common/src/platform/abstractions/state.service.ts +++ b/libs/common/src/platform/abstractions/state.service.ts @@ -170,14 +170,6 @@ export abstract class StateService { * @deprecated Do not call this directly, use SendService */ setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise; - /** - * @deprecated Do not call this, use SettingsService - */ - getDisableFavicon: (options?: StorageOptions) => Promise; - /** - * @deprecated Do not call this, use SettingsService - */ - setDisableFavicon: (value: boolean, options?: StorageOptions) => Promise; getDisableGa: (options?: StorageOptions) => Promise; setDisableGa: (value: boolean, options?: StorageOptions) => Promise; getDuckDuckGoSharedKey: (options?: StorageOptions) => Promise; diff --git a/libs/common/src/platform/models/domain/global-state.ts b/libs/common/src/platform/models/domain/global-state.ts index 0b018aa36b5..b27bac3bd42 100644 --- a/libs/common/src/platform/models/domain/global-state.ts +++ b/libs/common/src/platform/models/domain/global-state.ts @@ -10,7 +10,6 @@ export class GlobalState { theme?: ThemeType = ThemeType.System; window?: WindowState = new WindowState(); twoFactorToken?: string; - disableFavicon?: boolean; biometricFingerprintValidated?: boolean; vaultTimeout?: number; vaultTimeoutAction?: string; diff --git a/libs/common/src/platform/services/state.service.ts b/libs/common/src/platform/services/state.service.ts index 6694b6ab3f7..31d69e868bf 100644 --- a/libs/common/src/platform/services/state.service.ts +++ b/libs/common/src/platform/services/state.service.ts @@ -710,27 +710,6 @@ export class StateService< ); } - async getDisableFavicon(options?: StorageOptions): Promise { - return ( - ( - await this.getGlobals( - this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()), - ) - )?.disableFavicon ?? false - ); - } - - async setDisableFavicon(value: boolean, options?: StorageOptions): Promise { - const globals = await this.getGlobals( - this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()), - ); - globals.disableFavicon = value; - await this.saveGlobals( - globals, - this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()), - ); - } - async getDisableGa(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) diff --git a/libs/common/src/services/settings.service.ts b/libs/common/src/services/settings.service.ts deleted file mode 100644 index 9a4d04a147d..00000000000 --- a/libs/common/src/services/settings.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { BehaviorSubject, concatMap } from "rxjs"; - -import { SettingsService as SettingsServiceAbstraction } from "../abstractions/settings.service"; -import { StateService } from "../platform/abstractions/state.service"; -import { Utils } from "../platform/misc/utils"; - -export class SettingsService implements SettingsServiceAbstraction { - protected _disableFavicon = new BehaviorSubject(null); - - disableFavicon$ = this._disableFavicon.asObservable(); - - constructor(private stateService: StateService) { - this.stateService.activeAccountUnlocked$ - .pipe( - concatMap(async (unlocked) => { - if (Utils.global.bitwardenContainerService == null) { - return; - } - - if (!unlocked) { - return; - } - - const disableFavicon = await this.stateService.getDisableFavicon(); - - this._disableFavicon.next(disableFavicon); - }), - ) - .subscribe(); - } - - async setDisableFavicon(value: boolean) { - this._disableFavicon.next(value); - await this.stateService.setDisableFavicon(value); - } - - getDisableFavicon(): boolean { - return this._disableFavicon.getValue(); - } -} diff --git a/libs/common/src/state-migrations/migrate.ts b/libs/common/src/state-migrations/migrate.ts index 3bb947d0bd2..000f08b392b 100644 --- a/libs/common/src/state-migrations/migrate.ts +++ b/libs/common/src/state-migrations/migrate.ts @@ -37,6 +37,7 @@ import { MoveBillingAccountProfileMigrator } from "./migrations/39-move-billing- import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked"; import { OrganizationMigrator } from "./migrations/40-move-organization-state-to-state-provider"; import { EventCollectionMigrator } from "./migrations/41-move-event-collection-to-state-provider"; +import { EnableFaviconMigrator } from "./migrations/42-move-enable-favicon-to-domain-settings-state-provider"; import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys"; import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key"; import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account"; @@ -45,7 +46,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting import { MinVersionMigrator } from "./migrations/min-version"; export const MIN_VERSION = 3; -export const CURRENT_VERSION = 41; +export const CURRENT_VERSION = 42; export type MinVersion = typeof MIN_VERSION; export function createMigrationBuilder() { @@ -88,7 +89,8 @@ export function createMigrationBuilder() { .with(TokenServiceStateProviderMigrator, 37, 38) .with(MoveBillingAccountProfileMigrator, 38, 39) .with(OrganizationMigrator, 39, 40) - .with(EventCollectionMigrator, 40, CURRENT_VERSION); + .with(EventCollectionMigrator, 40, 41) + .with(EnableFaviconMigrator, 41, 42); } export async function currentVersion( diff --git a/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.spec.ts b/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.spec.ts new file mode 100644 index 00000000000..ddb3bd99072 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.spec.ts @@ -0,0 +1,108 @@ +import { MockProxy } from "jest-mock-extended"; + +import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; +import { mockMigrationHelper } from "../migration-helper.spec"; + +import { EnableFaviconMigrator } from "./42-move-enable-favicon-to-domain-settings-state-provider"; + +function exampleJSON() { + return { + global: { + otherStuff: "otherStuff1", + disableFavicon: true, + }, + authenticatedAccounts: ["user-1", "user-2"], + "user-1": { + settings: { + otherStuff: "otherStuff2", + }, + otherStuff: "otherStuff3", + }, + "user-2": { + settings: { + otherStuff: "otherStuff4", + }, + otherStuff: "otherStuff5", + }, + }; +} + +function rollbackJSON() { + return { + global_domainSettings_showFavicons: false, + global: { + otherStuff: "otherStuff1", + }, + authenticatedAccounts: ["user-1", "user-2"], + "user-1": { + settings: { + otherStuff: "otherStuff2", + }, + otherStuff: "otherStuff3", + }, + "user-2": { + settings: { + otherStuff: "otherStuff4", + }, + otherStuff: "otherStuff5", + }, + }; +} + +const showFaviconsKeyDefinition: KeyDefinitionLike = { + stateDefinition: { + name: "domainSettings", + }, + key: "showFavicons", +}; + +describe("EnableFaviconMigrator", () => { + let helper: MockProxy; + let sut: EnableFaviconMigrator; + + describe("migrate", () => { + beforeEach(() => { + helper = mockMigrationHelper(exampleJSON(), 41); + sut = new EnableFaviconMigrator(41, 42); + }); + + it("should remove global disableFavicon", async () => { + await sut.migrate(helper); + expect(helper.set).toHaveBeenCalledTimes(1); + expect(helper.set).toHaveBeenCalledWith("global", { + otherStuff: "otherStuff1", + }); + }); + + it("should set global showFavicons", async () => { + await sut.migrate(helper); + + expect(helper.setToGlobal).toHaveBeenCalledTimes(1); + expect(helper.setToGlobal).toHaveBeenCalledWith(showFaviconsKeyDefinition, false); + }); + }); + + describe("rollback", () => { + beforeEach(() => { + helper = mockMigrationHelper(rollbackJSON(), 42); + sut = new EnableFaviconMigrator(41, 42); + }); + + it("should null global showFavicons", async () => { + await sut.rollback(helper); + + expect(helper.setToGlobal).toHaveBeenCalledTimes(1); + expect(helper.setToGlobal).toHaveBeenCalledWith(showFaviconsKeyDefinition, null); + }); + + it("should add global disableFavicon back", async () => { + await sut.rollback(helper); + + expect(helper.set).toHaveBeenCalledTimes(1); + expect(helper.set).toHaveBeenCalledWith("global", { + disableFavicon: true, + otherStuff: "otherStuff1", + }); + }); + }); +}); diff --git a/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.ts b/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.ts new file mode 100644 index 00000000000..7da988ad8f6 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/42-move-enable-favicon-to-domain-settings-state-provider.ts @@ -0,0 +1,45 @@ +import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; +import { Migrator } from "../migrator"; + +type ExpectedGlobalState = { + disableFavicon?: boolean; +}; + +const ShowFaviconDefinition: KeyDefinitionLike = { + stateDefinition: { + name: "domainSettings", + }, + key: "showFavicons", +}; + +export class EnableFaviconMigrator extends Migrator<41, 42> { + async migrate(helper: MigrationHelper): Promise { + // global state ("disableFavicon" -> "showFavicons") + const globalState = await helper.get("global"); + + if (globalState?.disableFavicon != null) { + await helper.setToGlobal(ShowFaviconDefinition, !globalState.disableFavicon); + + // delete `disableFavicon` from state global + delete globalState.disableFavicon; + + await helper.set("global", globalState); + } + } + + async rollback(helper: MigrationHelper): Promise { + // global state ("showFavicons" -> "disableFavicon") + const globalState = (await helper.get("global")) || {}; + const showFavicons: boolean = await helper.getFromGlobal(ShowFaviconDefinition); + + if (showFavicons != null) { + await helper.set("global", { + ...globalState, + disableFavicon: !showFavicons, + }); + + // remove the global state provider framework key for `showFavicons` + await helper.setToGlobal(ShowFaviconDefinition, null); + } + } +} diff --git a/libs/common/src/vault/icon/build-cipher-icon.ts b/libs/common/src/vault/icon/build-cipher-icon.ts index 80bc5cbe3ae..9e6e671f44d 100644 --- a/libs/common/src/vault/icon/build-cipher-icon.ts +++ b/libs/common/src/vault/icon/build-cipher-icon.ts @@ -2,12 +2,7 @@ import { Utils } from "../../platform/misc/utils"; import { CipherType } from "../enums/cipher-type"; import { CipherView } from "../models/view/cipher.view"; -export function buildCipherIcon( - iconsServerUrl: string, - cipher: CipherView, - isFaviconDisabled: boolean, -) { - const imageEnabled = !isFaviconDisabled; +export function buildCipherIcon(iconsServerUrl: string, cipher: CipherView, showFavicon: boolean) { let icon; let image; let fallbackImage = ""; @@ -38,17 +33,17 @@ export function buildCipherIcon( icon = "bwi-apple"; image = null; } else if ( - imageEnabled && + showFavicon && hostnameUri.indexOf("://") === -1 && hostnameUri.indexOf(".") > -1 ) { hostnameUri = `http://${hostnameUri}`; isWebsite = true; - } else if (imageEnabled) { + } else if (showFavicon) { isWebsite = hostnameUri.indexOf("http") === 0 && hostnameUri.indexOf(".") > -1; } - if (imageEnabled && isWebsite) { + if (showFavicon && isWebsite) { try { image = `${iconsServerUrl}/${Utils.getHostname(hostnameUri)}/icon.png`; fallbackImage = "images/bwi-globe.png"; @@ -65,7 +60,7 @@ export function buildCipherIcon( break; case CipherType.Card: icon = "bwi-credit-card"; - if (imageEnabled && cipher.card.brand in cardIcons) { + if (showFavicon && cipher.card.brand in cardIcons) { icon = `credit-card-icon ${cardIcons[cipher.card.brand]}`; } break; @@ -77,7 +72,7 @@ export function buildCipherIcon( } return { - imageEnabled, + imageEnabled: showFavicon, image, fallbackImage, icon,