From 8e995da0d44dd78eed57c5c8ad737f1bd9f78e7e Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Fri, 4 Oct 2024 16:45:38 -0400 Subject: [PATCH] add experimental user settings service --- .../src/popup/services/services.module.ts | 9 ++ .../src/services/jslib-services.module.ts | 9 ++ .../services/labs-settings.service.ts | 92 +++++++++++++++++++ .../src/platform/state/state-definitions.ts | 4 + 4 files changed, 114 insertions(+) create mode 100644 libs/common/src/autofill/services/labs-settings.service.ts diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index f46386449f..188ff7f5e7 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -34,6 +34,10 @@ import { AutofillSettingsService, AutofillSettingsServiceAbstraction, } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { + LabsSettingsService, + LabsSettingsServiceAbstraction, +} from "@bitwarden/common/autofill/services/labs-settings.service"; import { DefaultDomainSettingsService, DomainSettingsService, @@ -453,6 +457,11 @@ const safeProviders: SafeProvider[] = [ useClass: AutofillSettingsService, deps: [StateProvider, PolicyService], }), + safeProvider({ + provide: LabsSettingsServiceAbstraction, + useClass: LabsSettingsService, + deps: [StateProvider, ConfigService], + }), safeProvider({ provide: UserNotificationSettingsServiceAbstraction, useClass: UserNotificationSettingsService, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index cc7af0c0b0..461ab51939 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -115,6 +115,10 @@ import { AutofillSettingsServiceAbstraction, AutofillSettingsService, } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { + LabsSettingsServiceAbstraction, + LabsSettingsService, +} from "@bitwarden/common/autofill/services/labs-settings.service"; import { BadgeSettingsServiceAbstraction, BadgeSettingsService, @@ -1205,6 +1209,11 @@ const safeProviders: SafeProvider[] = [ useClass: AutofillSettingsService, deps: [StateProvider, PolicyServiceAbstraction], }), + safeProvider({ + provide: LabsSettingsServiceAbstraction, + useClass: LabsSettingsService, + deps: [StateProvider, ConfigService], + }), safeProvider({ provide: BadgeSettingsServiceAbstraction, useClass: BadgeSettingsService, diff --git a/libs/common/src/autofill/services/labs-settings.service.ts b/libs/common/src/autofill/services/labs-settings.service.ts new file mode 100644 index 0000000000..bd8102a92f --- /dev/null +++ b/libs/common/src/autofill/services/labs-settings.service.ts @@ -0,0 +1,92 @@ +import { map, Observable, firstValueFrom } from "rxjs"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags"; + +import { + LABS_SETTINGS_DISK, + LABS_SETTINGS_DISK_LOCAL, + ActiveUserState, + GlobalState, + KeyDefinition, + StateProvider, + UserKeyDefinition, +} from "../../platform/state"; + +const LABS_SETTINGS_ENABLED = new UserKeyDefinition(LABS_SETTINGS_DISK, "labsSettingsEnabled", { + deserializer: (value: boolean) => value ?? false, + clearOn: [], +}); + +const IMPROVED_FIELD_QUALIFICATION_FOR_INLINE_MENU_ENABLED = new UserKeyDefinition( + LABS_SETTINGS_DISK, + "improvedFieldQualificationForInlineMenuEnabled", + { + deserializer: (value: boolean) => value ?? null, + clearOn: [], + }, +); + +const ADDITIONAL_INLINE_MENU_CIPHER_TYPES_ENABLED = new UserKeyDefinition( + LABS_SETTINGS_DISK, + "additionalInlineMenuCipherTypesEnabled", + { + deserializer: (value: boolean) => value ?? null, + clearOn: [], + }, +); + +export abstract class LabsSettingsServiceAbstraction { + labsSettingsEnabled$: Observable; + setLabsSettingsEnabled: (newValue: boolean) => Promise; + improvedFieldQualificationForInlineMenuEnabled$: Observable; + setImprovedFieldQualificationForInlineMenuEnabled: (newValue: boolean) => Promise; + additionalInlineMenuCipherTypesEnabled$: Observable; + setAdditionalInlineMenuCipherTypesEnabled: (newValue: boolean) => Promise; +} + +export class LabsSettingsService implements LabsSettingsServiceAbstraction { + private labsSettingsEnabledState: ActiveUserState; + readonly labsSettingsEnabled$: Observable; + private improvedFieldQualificationForInlineMenuEnabledState: ActiveUserState; + readonly improvedFieldQualificationForInlineMenuEnabled$: Observable; + private additionalInlineMenuCipherTypesEnabledState: ActiveUserState; + readonly additionalInlineMenuCipherTypesEnabled$: Observable; + + constructor( + private stateProvider: StateProvider, + private configService: ConfigService, + ) { + this.labsSettingsEnabledState = this.stateProvider.getActive(LABS_SETTINGS_ENABLED); + this.labsSettingsEnabled$ = this.labsSettingsEnabledState.state$.pipe(map((x) => x ?? false)); + + this.improvedFieldQualificationForInlineMenuEnabledState = this.stateProvider.getActive( + IMPROVED_FIELD_QUALIFICATION_FOR_INLINE_MENU_ENABLED, + ); + this.improvedFieldQualificationForInlineMenuEnabled$ = + this.improvedFieldQualificationForInlineMenuEnabledState.state$.pipe(map((x) => x ?? null)); + + this.additionalInlineMenuCipherTypesEnabledState = this.stateProvider.getActive( + ADDITIONAL_INLINE_MENU_CIPHER_TYPES_ENABLED, + ); + this.additionalInlineMenuCipherTypesEnabled$ = + this.additionalInlineMenuCipherTypesEnabledState.state$.pipe(map((x) => x ?? null)); + } + + async init() { + } + + async setLabsSettingsEnabled(newValue: boolean): Promise { + await this.labsSettingsEnabledState.update(() => newValue); + } + + // This setting may improve the accuracy of the inline menu appearing in login forms + async setImprovedFieldQualificationForInlineMenuEnabled(newValue: boolean): Promise { + await this.improvedFieldQualificationForInlineMenuEnabledState.update(() => newValue); + } + + // This flag turns on inline menu credit card and identity features + async setAdditionalInlineMenuCipherTypesEnabled(newValue: boolean): Promise { + await this.additionalInlineMenuCipherTypesEnabledState.update(() => newValue); + } +} diff --git a/libs/common/src/platform/state/state-definitions.ts b/libs/common/src/platform/state/state-definitions.ts index 47b7199b94..fc62d00bf7 100644 --- a/libs/common/src/platform/state/state-definitions.ts +++ b/libs/common/src/platform/state/state-definitions.ts @@ -85,6 +85,10 @@ export const USER_NOTIFICATION_SETTINGS_DISK = new StateDefinition( "disk", ); +export const LABS_SETTINGS_DISK = new StateDefinition("labsSettings", "disk"); +export const LABS_SETTINGS_DISK_LOCAL = new StateDefinition("labsSettingsLocal", "disk", { + web: "disk-local", +}); export const DOMAIN_SETTINGS_DISK = new StateDefinition("domainSettings", "disk"); export const AUTOFILL_SETTINGS_DISK = new StateDefinition("autofillSettings", "disk"); export const AUTOFILL_SETTINGS_DISK_LOCAL = new StateDefinition("autofillSettingsLocal", "disk", {