mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
Migrate autoConfirmFingerPrints
to StateProvider
(#8337)
* Fix a typo in the `StateDefinition` description * Introduce `OrganizationManagementPreferencesService` * Declare `OrganizationManagementPreferencesService` in DI * Update `autoConfirmFingerPrints` logic in emergency access files * Update `autoConfirmFingerPrints` logic in `people` files * Remove `autoConfirmFingerPrints` from `StateService` and `Account` * Migrate existing client data for `autoConfirmFingerPrints` * Update apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Update apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Use `set` instead of `update` for function names --------- Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
parent
3953318c28
commit
bf2d2cfbed
@ -1,10 +1,12 @@
|
|||||||
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
||||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import {
|
import {
|
||||||
OrganizationUserStatusType,
|
OrganizationUserStatusType,
|
||||||
OrganizationUserType,
|
OrganizationUserType,
|
||||||
@ -17,7 +19,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
@ -109,8 +110,8 @@ export abstract class BasePeopleComponent<
|
|||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private searchPipe: SearchPipe,
|
private searchPipe: SearchPipe,
|
||||||
protected userNamePipe: UserNamePipe,
|
protected userNamePipe: UserNamePipe,
|
||||||
protected stateService: StateService,
|
|
||||||
protected dialogService: DialogService,
|
protected dialogService: DialogService,
|
||||||
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
abstract edit(user: UserType): void;
|
abstract edit(user: UserType): void;
|
||||||
@ -351,7 +352,9 @@ export abstract class BasePeopleComponent<
|
|||||||
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
||||||
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
||||||
|
|
||||||
const autoConfirm = await this.stateService.getAutoConfirmFingerPrints();
|
const autoConfirm = await firstValueFrom(
|
||||||
|
this.organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
if (autoConfirm == null || !autoConfirm) {
|
if (autoConfirm == null || !autoConfirm) {
|
||||||
const [modal] = await this.modalService.openViewRef(
|
const [modal] = await this.modalService.openViewRef(
|
||||||
UserConfirmComponent,
|
UserConfirmComponent,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
|
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-user-confirm",
|
selector: "app-user-confirm",
|
||||||
@ -22,7 +22,7 @@ export class UserConfirmComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private stateService: StateService,
|
private organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@ -45,7 +45,7 @@ export class UserConfirmComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.dontAskAgain) {
|
if (this.dontAskAgain) {
|
||||||
await this.stateService.setAutoConfirmFingerprints(true);
|
await this.organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onConfirmedUser.emit();
|
this.onConfirmedUser.emit();
|
||||||
|
@ -21,6 +21,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
import { OrganizationUserConfirmRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
import { OrganizationUserConfirmRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
||||||
import {
|
import {
|
||||||
@ -43,7 +44,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
@ -117,7 +117,6 @@ export class PeopleComponent
|
|||||||
searchPipe: SearchPipe,
|
searchPipe: SearchPipe,
|
||||||
userNamePipe: UserNamePipe,
|
userNamePipe: UserNamePipe,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
stateService: StateService,
|
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
private organizationUserService: OrganizationUserService,
|
private organizationUserService: OrganizationUserService,
|
||||||
@ -125,6 +124,7 @@ export class PeopleComponent
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private groupService: GroupService,
|
private groupService: GroupService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
|
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
apiService,
|
apiService,
|
||||||
@ -137,8 +137,8 @@ export class PeopleComponent
|
|||||||
logService,
|
logService,
|
||||||
searchPipe,
|
searchPipe,
|
||||||
userNamePipe,
|
userNamePipe,
|
||||||
stateService,
|
|
||||||
dialogService,
|
dialogService,
|
||||||
|
organizationManagementPreferencesService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@ import { Component, OnInit, Inject } from "@angular/core";
|
|||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export class EmergencyAccessConfirmComponent implements OnInit {
|
|||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private stateService: StateService,
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private dialogRef: DialogRef<EmergencyAccessConfirmDialogResult>,
|
private dialogRef: DialogRef<EmergencyAccessConfirmDialogResult>,
|
||||||
) {}
|
) {}
|
||||||
@ -63,7 +63,7 @@ export class EmergencyAccessConfirmComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.confirmForm.get("dontAskAgain").value) {
|
if (this.confirmForm.get("dontAskAgain").value) {
|
||||||
await this.stateService.setAutoConfirmFingerprints(true);
|
await this.organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -3,6 +3,7 @@ import { lastValueFrom, Observable, firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@ -64,6 +65,7 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
protected dialogService: DialogService,
|
protected dialogService: DialogService,
|
||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||||
}
|
}
|
||||||
@ -136,7 +138,9 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoConfirm = await this.stateService.getAutoConfirmFingerPrints();
|
const autoConfirm = await firstValueFrom(
|
||||||
|
this.organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
if (autoConfirm == null || !autoConfirm) {
|
if (autoConfirm == null || !autoConfirm) {
|
||||||
const dialogRef = EmergencyAccessConfirmComponent.open(this.dialogService, {
|
const dialogRef = EmergencyAccessConfirmComponent.open(this.dialogService, {
|
||||||
data: {
|
data: {
|
||||||
|
@ -7,6 +7,7 @@ import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
|||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||||
import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
|
import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request";
|
import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request";
|
||||||
@ -18,7 +19,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { BasePeopleComponent } from "@bitwarden/web-vault/app/admin-console/common/base.people.component";
|
import { BasePeopleComponent } from "@bitwarden/web-vault/app/admin-console/common/base.people.component";
|
||||||
@ -67,9 +67,9 @@ export class PeopleComponent
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
searchPipe: SearchPipe,
|
searchPipe: SearchPipe,
|
||||||
userNamePipe: UserNamePipe,
|
userNamePipe: UserNamePipe,
|
||||||
stateService: StateService,
|
|
||||||
private providerService: ProviderService,
|
private providerService: ProviderService,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
|
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
apiService,
|
apiService,
|
||||||
@ -82,8 +82,8 @@ export class PeopleComponent
|
|||||||
logService,
|
logService,
|
||||||
searchPipe,
|
searchPipe,
|
||||||
userNamePipe,
|
userNamePipe,
|
||||||
stateService,
|
|
||||||
dialogService,
|
dialogService,
|
||||||
|
organizationManagementPreferencesService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import {
|
|||||||
OrgDomainInternalServiceAbstraction,
|
OrgDomainInternalServiceAbstraction,
|
||||||
OrgDomainServiceAbstraction,
|
OrgDomainServiceAbstraction,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
@ -38,6 +39,7 @@ import { OrganizationApiService } from "@bitwarden/common/admin-console/services
|
|||||||
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
||||||
import { OrgDomainApiService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain-api.service";
|
import { OrgDomainApiService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain-api.service";
|
||||||
import { OrgDomainService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain.service";
|
import { OrgDomainService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain.service";
|
||||||
|
import { DefaultOrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/services/organization-management-preferences/default-organization-management-preferences.service";
|
||||||
import { OrganizationUserServiceImplementation } from "@bitwarden/common/admin-console/services/organization-user/organization-user.service.implementation";
|
import { OrganizationUserServiceImplementation } from "@bitwarden/common/admin-console/services/organization-user/organization-user.service.implementation";
|
||||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||||
@ -1048,6 +1050,11 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
useClass: DefaultBillingAccountProfileStateService,
|
useClass: DefaultBillingAccountProfileStateService,
|
||||||
deps: [ActiveUserStateProvider],
|
deps: [ActiveUserStateProvider],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: OrganizationManagementPreferencesService,
|
||||||
|
useClass: DefaultOrganizationManagementPreferencesService,
|
||||||
|
deps: [StateProvider],
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
function encryptServiceFactory(
|
function encryptServiceFactory(
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the state of a single organization management preference.
|
||||||
|
* Can be used to subscribe to or update a given property.
|
||||||
|
*/
|
||||||
|
export class OrganizationManagementPreference<T> {
|
||||||
|
state$: Observable<T>;
|
||||||
|
set: (value: T) => Promise<void>;
|
||||||
|
|
||||||
|
constructor(state$: Observable<T>, setFn: (value: T) => Promise<void>) {
|
||||||
|
this.state$ = state$;
|
||||||
|
this.set = setFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes state of a given user's personal settings relating to the user experience of managing an organization.
|
||||||
|
*/
|
||||||
|
export abstract class OrganizationManagementPreferencesService {
|
||||||
|
autoConfirmFingerPrints: OrganizationManagementPreference<boolean>;
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import { MockProxy } from "jest-mock-extended";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { FakeStateProvider, mockAccountServiceWith } from "../../../../spec";
|
||||||
|
import { UserId } from "../../../types/guid";
|
||||||
|
|
||||||
|
import { DefaultOrganizationManagementPreferencesService } from "./default-organization-management-preferences.service";
|
||||||
|
|
||||||
|
describe("OrganizationManagementPreferencesService", () => {
|
||||||
|
let stateProvider: FakeStateProvider;
|
||||||
|
let organizationManagementPreferencesService: MockProxy<DefaultOrganizationManagementPreferencesService>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const accountService = mockAccountServiceWith("userId" as UserId);
|
||||||
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
organizationManagementPreferencesService = new DefaultOrganizationManagementPreferencesService(
|
||||||
|
stateProvider,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("autoConfirmFingerPrints", () => {
|
||||||
|
it("returns false by default", async () => {
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(false);
|
||||||
|
});
|
||||||
|
it("returns true if set", async () => {
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(true);
|
||||||
|
});
|
||||||
|
it("can be unset", async () => {
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(false);
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,71 @@
|
|||||||
|
import { map } from "rxjs";
|
||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ORGANIZATION_MANAGEMENT_PREFERENCES_DISK,
|
||||||
|
StateProvider,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "../../../platform/state";
|
||||||
|
import {
|
||||||
|
OrganizationManagementPreference,
|
||||||
|
OrganizationManagementPreferencesService,
|
||||||
|
} from "../../abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This helper function can be used to quickly create `KeyDefinitions` that
|
||||||
|
* target the `ORGANIZATION_MANAGEMENT_PREFERENCES_DISK` `StateDefinition`
|
||||||
|
* and that have the default deserializer and `clearOn` options. Any
|
||||||
|
* contenders for options to add to this service will likely use these same
|
||||||
|
* options.
|
||||||
|
*/
|
||||||
|
function buildKeyDefinition<T>(key: string): UserKeyDefinition<T> {
|
||||||
|
return new UserKeyDefinition<T>(ORGANIZATION_MANAGEMENT_PREFERENCES_DISK, key, {
|
||||||
|
deserializer: (obj: Jsonify<T>) => obj as T,
|
||||||
|
clearOn: ["logout"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AUTO_CONFIRM_FINGERPRINTS = buildKeyDefinition<boolean>("autoConfirmFingerPrints");
|
||||||
|
|
||||||
|
export class DefaultOrganizationManagementPreferencesService
|
||||||
|
implements OrganizationManagementPreferencesService
|
||||||
|
{
|
||||||
|
constructor(private stateProvider: StateProvider) {}
|
||||||
|
|
||||||
|
autoConfirmFingerPrints = this.buildOrganizationManagementPreference(
|
||||||
|
AUTO_CONFIRM_FINGERPRINTS,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an `OrganizationManagementPreference` object for the provided
|
||||||
|
* `KeyDefinition`. This object can then be used by callers to subscribe to
|
||||||
|
* a given key, or set its value in state.
|
||||||
|
*/
|
||||||
|
private buildOrganizationManagementPreference<T>(
|
||||||
|
keyDefinition: UserKeyDefinition<T>,
|
||||||
|
defaultValue: T,
|
||||||
|
) {
|
||||||
|
return new OrganizationManagementPreference<T>(
|
||||||
|
this.getKeyFromState(keyDefinition).state$.pipe(map((x) => x ?? defaultValue)),
|
||||||
|
this.setKeyInStateFn(keyDefinition),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the full `ActiveUserState` value for a given `keyDefinition`
|
||||||
|
* The returned value can then be called for subscription || set operations
|
||||||
|
*/
|
||||||
|
private getKeyFromState<T>(keyDefinition: UserKeyDefinition<T>) {
|
||||||
|
return this.stateProvider.getActive(keyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function that can be called to set the given `keyDefinition` in state
|
||||||
|
*/
|
||||||
|
private setKeyInStateFn<T>(keyDefinition: UserKeyDefinition<T>) {
|
||||||
|
return async (value: T) => {
|
||||||
|
await this.getKeyFromState(keyDefinition).update(() => value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -54,9 +54,6 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
setAddEditCipherInfo: (value: AddEditCipherInfo, options?: StorageOptions) => Promise<void>;
|
setAddEditCipherInfo: (value: AddEditCipherInfo, options?: StorageOptions) => Promise<void>;
|
||||||
getAlwaysShowDock: (options?: StorageOptions) => Promise<boolean>;
|
getAlwaysShowDock: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setAlwaysShowDock: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setAlwaysShowDock: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
|
|
||||||
getAutoConfirmFingerPrints: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setAutoConfirmFingerprints: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setBiometricFingerprintValidated: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setBiometricFingerprintValidated: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getConvertAccountToKeyConnector: (options?: StorageOptions) => Promise<boolean>;
|
getConvertAccountToKeyConnector: (options?: StorageOptions) => Promise<boolean>;
|
||||||
|
@ -187,7 +187,6 @@ export class AccountProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AccountSettings {
|
export class AccountSettings {
|
||||||
autoConfirmFingerPrints?: boolean;
|
|
||||||
defaultUriMatch?: UriMatchStrategySetting;
|
defaultUriMatch?: UriMatchStrategySetting;
|
||||||
disableGa?: boolean;
|
disableGa?: boolean;
|
||||||
enableAlwaysOnTop?: boolean;
|
enableAlwaysOnTop?: boolean;
|
||||||
|
@ -300,24 +300,6 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAutoConfirmFingerPrints(options?: StorageOptions): Promise<boolean> {
|
|
||||||
return (
|
|
||||||
(await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
|
||||||
?.settings?.autoConfirmFingerPrints ?? false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setAutoConfirmFingerprints(value: boolean, options?: StorageOptions): Promise<void> {
|
|
||||||
const account = await this.getAccount(
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
account.settings.autoConfirmFingerPrints = value;
|
|
||||||
await this.saveAccount(
|
|
||||||
account,
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBiometricFingerprintValidated(options?: StorageOptions): Promise<boolean> {
|
async getBiometricFingerprintValidated(options?: StorageOptions): Promise<boolean> {
|
||||||
return (
|
return (
|
||||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
* Default storage location options.
|
* Default storage location options.
|
||||||
*
|
*
|
||||||
* `disk` generally means state that is accessible between restarts of the application,
|
* `disk` generally means state that is accessible between restarts of the application,
|
||||||
* with the exception of the web client. In web this means `sessionStorage`. The data is
|
* with the exception of the web client. In web this means `sessionStorage`. The data
|
||||||
* through refreshes of the page but not available once that tab is closed or from any
|
* persists through refreshes of the page but not available once that tab is closed or
|
||||||
* other tabs.
|
* from any other tabs.
|
||||||
*
|
*
|
||||||
* `memory` means that the information stored there goes away during application
|
* `memory` means that the information stored there goes away during application
|
||||||
* restarts.
|
* restarts.
|
||||||
|
@ -22,6 +22,13 @@ import { StateDefinition } from "./state-definition";
|
|||||||
export const ORGANIZATIONS_DISK = new StateDefinition("organizations", "disk");
|
export const ORGANIZATIONS_DISK = new StateDefinition("organizations", "disk");
|
||||||
export const POLICIES_DISK = new StateDefinition("policies", "disk");
|
export const POLICIES_DISK = new StateDefinition("policies", "disk");
|
||||||
export const PROVIDERS_DISK = new StateDefinition("providers", "disk");
|
export const PROVIDERS_DISK = new StateDefinition("providers", "disk");
|
||||||
|
export const ORGANIZATION_MANAGEMENT_PREFERENCES_DISK = new StateDefinition(
|
||||||
|
"organizationManagementPreferences",
|
||||||
|
"disk",
|
||||||
|
{
|
||||||
|
web: "disk-local",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Billing
|
// Billing
|
||||||
export const BILLING_DISK = new StateDefinition("billing", "disk");
|
export const BILLING_DISK = new StateDefinition("billing", "disk");
|
||||||
|
@ -38,6 +38,7 @@ import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-
|
|||||||
import { OrganizationMigrator } from "./migrations/40-move-organization-state-to-state-provider";
|
import { OrganizationMigrator } from "./migrations/40-move-organization-state-to-state-provider";
|
||||||
import { EventCollectionMigrator } from "./migrations/41-move-event-collection-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 { EnableFaviconMigrator } from "./migrations/42-move-enable-favicon-to-domain-settings-state-provider";
|
||||||
|
import { AutoConfirmFingerPrintsMigrator } from "./migrations/43-move-auto-confirm-finger-prints-to-state-provider";
|
||||||
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
||||||
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
||||||
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
||||||
@ -46,7 +47,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
|||||||
import { MinVersionMigrator } from "./migrations/min-version";
|
import { MinVersionMigrator } from "./migrations/min-version";
|
||||||
|
|
||||||
export const MIN_VERSION = 3;
|
export const MIN_VERSION = 3;
|
||||||
export const CURRENT_VERSION = 42;
|
export const CURRENT_VERSION = 43;
|
||||||
export type MinVersion = typeof MIN_VERSION;
|
export type MinVersion = typeof MIN_VERSION;
|
||||||
|
|
||||||
export function createMigrationBuilder() {
|
export function createMigrationBuilder() {
|
||||||
@ -90,7 +91,8 @@ export function createMigrationBuilder() {
|
|||||||
.with(MoveBillingAccountProfileMigrator, 38, 39)
|
.with(MoveBillingAccountProfileMigrator, 38, 39)
|
||||||
.with(OrganizationMigrator, 39, 40)
|
.with(OrganizationMigrator, 39, 40)
|
||||||
.with(EventCollectionMigrator, 40, 41)
|
.with(EventCollectionMigrator, 40, 41)
|
||||||
.with(EnableFaviconMigrator, 41, 42);
|
.with(EnableFaviconMigrator, 41, 42)
|
||||||
|
.with(AutoConfirmFingerPrintsMigrator, 42, CURRENT_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function currentVersion(
|
export async function currentVersion(
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
import { MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
|
import { MigrationHelper } from "../migration-helper";
|
||||||
|
import { mockMigrationHelper, runMigrator } from "../migration-helper.spec";
|
||||||
|
|
||||||
|
import { AutoConfirmFingerPrintsMigrator } from "./43-move-auto-confirm-finger-prints-to-state-provider";
|
||||||
|
|
||||||
|
function rollbackJSON() {
|
||||||
|
return {
|
||||||
|
authenticatedAccounts: ["user-1", "user-2"],
|
||||||
|
"user_user-1_organizationManagementPreferences_autoConfirmFingerPrints": true,
|
||||||
|
"user_user-2_organizationManagementPreferences_autoConfirmFingerPrints": false,
|
||||||
|
"user-1": {
|
||||||
|
settings: {
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
"user-2": {
|
||||||
|
settings: {
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("AutoConfirmFingerPrintsMigrator", () => {
|
||||||
|
const migrator = new AutoConfirmFingerPrintsMigrator(42, 43);
|
||||||
|
|
||||||
|
it("should migrate the autoConfirmFingerPrints property from the account settings object to a user StorageKey", async () => {
|
||||||
|
const output = await runMigrator(migrator, {
|
||||||
|
authenticatedAccounts: ["user-1", "user-2"] as const,
|
||||||
|
"user-1": {
|
||||||
|
settings: {
|
||||||
|
autoConfirmFingerPrints: true,
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
"user-2": {
|
||||||
|
settings: {
|
||||||
|
autoConfirmFingerPrints: false,
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(output).toEqual({
|
||||||
|
authenticatedAccounts: ["user-1", "user-2"],
|
||||||
|
"user_user-1_organizationManagementPreferences_autoConfirmFingerPrints": true,
|
||||||
|
"user_user-2_organizationManagementPreferences_autoConfirmFingerPrints": false,
|
||||||
|
"user-1": {
|
||||||
|
settings: {
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
"user-2": {
|
||||||
|
settings: {
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("rollback", () => {
|
||||||
|
let helper: MockProxy<MigrationHelper>;
|
||||||
|
let sut: AutoConfirmFingerPrintsMigrator;
|
||||||
|
|
||||||
|
const keyDefinitionLike = {
|
||||||
|
key: "autoConfirmFingerPrints",
|
||||||
|
stateDefinition: {
|
||||||
|
name: "organizationManagementPreferences",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
helper = mockMigrationHelper(rollbackJSON(), 43);
|
||||||
|
sut = new AutoConfirmFingerPrintsMigrator(42, 43);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should null the autoConfirmFingerPrints user StorageKey for each account", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledWith("user-1", keyDefinitionLike, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add the autoConfirmFingerPrints property back to the account settings object", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||||
|
settings: {
|
||||||
|
autoConfirmFingerPrints: true,
|
||||||
|
extra: "data",
|
||||||
|
},
|
||||||
|
extra: "data",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,63 @@
|
|||||||
|
import { KeyDefinitionLike, MigrationHelper, StateDefinitionLike } from "../migration-helper";
|
||||||
|
import { Migrator } from "../migrator";
|
||||||
|
|
||||||
|
type ExpectedAccountState = {
|
||||||
|
settings?: { autoConfirmFingerPrints?: boolean };
|
||||||
|
};
|
||||||
|
|
||||||
|
const ORGANIZATION_MANAGEMENT_PREFERENCES: StateDefinitionLike = {
|
||||||
|
name: "organizationManagementPreferences",
|
||||||
|
};
|
||||||
|
|
||||||
|
const AUTO_CONFIRM_FINGERPRINTS: KeyDefinitionLike = {
|
||||||
|
key: "autoConfirmFingerPrints",
|
||||||
|
stateDefinition: ORGANIZATION_MANAGEMENT_PREFERENCES,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AutoConfirmFingerPrintsMigrator extends Migrator<42, 43> {
|
||||||
|
async migrate(helper: MigrationHelper): Promise<void> {
|
||||||
|
const legacyAccounts = await helper.getAccounts<ExpectedAccountState>();
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
legacyAccounts.map(async ({ userId, account }) => {
|
||||||
|
if (account?.settings?.autoConfirmFingerPrints != null) {
|
||||||
|
await helper.setToUser(
|
||||||
|
userId,
|
||||||
|
AUTO_CONFIRM_FINGERPRINTS,
|
||||||
|
account.settings.autoConfirmFingerPrints,
|
||||||
|
);
|
||||||
|
delete account?.settings?.autoConfirmFingerPrints;
|
||||||
|
await helper.set(userId, account);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async rollback(helper: MigrationHelper): Promise<void> {
|
||||||
|
async function rollbackUser(userId: string, account: ExpectedAccountState) {
|
||||||
|
let updatedAccount = false;
|
||||||
|
const autoConfirmFingerPrints = await helper.getFromUser<boolean>(
|
||||||
|
userId,
|
||||||
|
AUTO_CONFIRM_FINGERPRINTS,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (autoConfirmFingerPrints) {
|
||||||
|
if (!account) {
|
||||||
|
account = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAccount = true;
|
||||||
|
account.settings.autoConfirmFingerPrints = autoConfirmFingerPrints;
|
||||||
|
await helper.setToUser(userId, AUTO_CONFIRM_FINGERPRINTS, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedAccount) {
|
||||||
|
await helper.set(userId, account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const accounts = await helper.getAccounts<ExpectedAccountState>();
|
||||||
|
|
||||||
|
await Promise.all(accounts.map(({ userId, account }) => rollbackUser(userId, account)));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user