mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[AC-2156] Billing State Provider Migration (#8133)
* Added billing account profile state service
* Update usages after removing state service functions
* Added migrator
* Updated bw.ts and main.background.ts
* Removed comment
* Updated state service dependencies to include billing service
* Added missing mv3 factory and updated MainContextMenuHandler
* updated autofill service and tests
* Updated the remaining extensions usages
* Updated desktop
* Removed subjects where they weren't needed
* Refactored billing service to have a single setter to avoid unecessary emissions
* Refactored has premium guard to return an observable
* Renamed services to match ADR
f633f2cdd8/docs/architecture/clients/presentation/angular.md (abstract--default-implementations)
* Updated property names to be a smidgen more descriptive and added jsdocs
* Updated setting of canAccessPremium to automatically update when the underlying observable emits
* Fixed build error after merge conflicts
* Another build error from conflict
* Removed autofill unit test changes from conflict
* Updated login strategy to not set premium field using state service
* Updated CLI to use billing state provider
* Shortened names a bit
* Fixed build
This commit is contained in:
@@ -41,6 +41,8 @@ import {
|
||||
DefaultDomainSettingsService,
|
||||
DomainSettingsService,
|
||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
@@ -221,6 +223,7 @@ export class Main {
|
||||
avatarService: AvatarServiceAbstraction;
|
||||
stateEventRunnerService: StateEventRunnerService;
|
||||
biometricStateService: BiometricStateService;
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService;
|
||||
|
||||
constructor() {
|
||||
let p = null;
|
||||
@@ -456,6 +459,10 @@ export class Main {
|
||||
this.stateService,
|
||||
);
|
||||
|
||||
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
||||
this.activeUserStateProvider,
|
||||
);
|
||||
|
||||
this.loginStrategyService = new LoginStrategyService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
@@ -475,6 +482,7 @@ export class Main {
|
||||
this.deviceTrustCryptoService,
|
||||
this.authRequestService,
|
||||
this.globalStateProvider,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
this.authService = new AuthService(
|
||||
@@ -586,6 +594,7 @@ export class Main {
|
||||
this.sendApiService,
|
||||
this.avatarService,
|
||||
async (expired: boolean) => await this.logout(),
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
this.totpService = new TotpService(this.cryptoFunctionService, this.logService);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { CardExport } from "@bitwarden/common/models/export/card.export";
|
||||
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
||||
@@ -57,6 +60,7 @@ export class GetCommand extends DownloadCommand {
|
||||
private apiService: ApiService,
|
||||
private organizationService: OrganizationService,
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(cryptoService);
|
||||
}
|
||||
@@ -251,7 +255,9 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.error("Couldn't generate TOTP code.");
|
||||
}
|
||||
|
||||
const canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.accountProfileService.hasPremiumFromAnySource$,
|
||||
);
|
||||
if (!canAccessPremium) {
|
||||
const originalCipher = await this.cipherService.get(cipher.id);
|
||||
if (
|
||||
@@ -334,7 +340,10 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.multipleResults(attachments.map((a) => a.id));
|
||||
}
|
||||
|
||||
if (!(await this.stateService.getCanAccessPremium())) {
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.accountProfileService.hasPremiumFromAnySource$,
|
||||
);
|
||||
if (!canAccessPremium) {
|
||||
const originalCipher = await this.cipherService.get(cipher.id);
|
||||
if (originalCipher == null || originalCipher.organizationId == null) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
|
||||
@@ -68,6 +68,7 @@ export class ServeCommand {
|
||||
this.main.apiService,
|
||||
this.main.organizationService,
|
||||
this.main.eventCollectionService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
this.listCommand = new ListCommand(
|
||||
this.main.cipherService,
|
||||
@@ -82,10 +83,10 @@ export class ServeCommand {
|
||||
this.createCommand = new CreateCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.cryptoService,
|
||||
this.main.apiService,
|
||||
this.main.folderApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
this.editCommand = new EditCommand(
|
||||
this.main.cipherService,
|
||||
@@ -108,9 +109,9 @@ export class ServeCommand {
|
||||
this.deleteCommand = new DeleteCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.apiService,
|
||||
this.main.folderApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
this.confirmCommand = new ConfirmCommand(
|
||||
this.main.apiService,
|
||||
@@ -135,9 +136,9 @@ export class ServeCommand {
|
||||
|
||||
this.sendCreateCommand = new SendCreateCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
this.main.environmentService,
|
||||
this.main.sendApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService, this.main.sendApiService);
|
||||
this.sendGetCommand = new SendGetCommand(
|
||||
@@ -148,9 +149,9 @@ export class ServeCommand {
|
||||
);
|
||||
this.sendEditCommand = new SendEditCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
this.sendGetCommand,
|
||||
this.main.sendApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
this.sendListCommand = new SendListCommand(
|
||||
this.main.sendService,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
@@ -16,9 +18,9 @@ import { SendResponse } from "../models/send.response";
|
||||
export class SendCreateCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private stateService: StateService,
|
||||
private environmentService: EnvironmentService,
|
||||
private sendApiService: SendApiService,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
async run(requestJson: any, cmdOptions: Record<string, any>) {
|
||||
@@ -82,7 +84,7 @@ export class SendCreateCommand {
|
||||
);
|
||||
}
|
||||
|
||||
if (!(await this.stateService.getCanAccessPremium())) {
|
||||
if (!(await firstValueFrom(this.accountProfileService.hasPremiumFromAnySource$))) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
@@ -12,9 +14,9 @@ import { SendGetCommand } from "./get.command";
|
||||
export class SendEditCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private stateService: StateService,
|
||||
private getCommand: SendGetCommand,
|
||||
private sendApiService: SendApiService,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
@@ -57,7 +59,10 @@ export class SendEditCommand {
|
||||
return Response.badRequest("Cannot change a Send's type");
|
||||
}
|
||||
|
||||
if (send.type === SendType.File && !(await this.stateService.getCanAccessPremium())) {
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.accountProfileService.hasPremiumFromAnySource$,
|
||||
);
|
||||
if (send.type === SendType.File && !canAccessPremium) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@ export class SendProgram extends Program {
|
||||
this.main.apiService,
|
||||
this.main.organizationService,
|
||||
this.main.eventCollectionService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
const response = await cmd.run("template", object, null);
|
||||
this.processResponse(response);
|
||||
@@ -253,9 +254,9 @@ export class SendProgram extends Program {
|
||||
);
|
||||
const cmd = new SendEditCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
getCmd,
|
||||
this.main.sendApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
const response = await cmd.run(encodedJson, options);
|
||||
this.processResponse(response);
|
||||
@@ -323,9 +324,9 @@ export class SendProgram extends Program {
|
||||
await this.exitIfLocked();
|
||||
const cmd = new SendCreateCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
this.main.environmentService,
|
||||
this.main.sendApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
return await cmd.run(encodedJson, options);
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@ export class VaultProgram extends Program {
|
||||
this.main.apiService,
|
||||
this.main.organizationService,
|
||||
this.main.eventCollectionService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
const response = await command.run(object, id, cmd);
|
||||
this.processResponse(response);
|
||||
@@ -226,10 +227,10 @@ export class VaultProgram extends Program {
|
||||
const command = new CreateCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.cryptoService,
|
||||
this.main.apiService,
|
||||
this.main.folderApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
const response = await command.run(object, encodedJson, cmd);
|
||||
this.processResponse(response);
|
||||
@@ -313,9 +314,9 @@ export class VaultProgram extends Program {
|
||||
const command = new DeleteCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.apiService,
|
||||
this.main.folderApiService,
|
||||
this.main.billingAccountProfileStateService,
|
||||
);
|
||||
const response = await command.run(object, id, cmd);
|
||||
this.processResponse(response);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
||||
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
||||
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
@@ -26,10 +28,10 @@ export class CreateCommand {
|
||||
constructor(
|
||||
private cipherService: CipherService,
|
||||
private folderService: FolderService,
|
||||
private stateService: StateService,
|
||||
private cryptoService: CryptoService,
|
||||
private apiService: ApiService,
|
||||
private folderApiService: FolderApiServiceAbstraction,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
async run(
|
||||
@@ -124,7 +126,10 @@ export class CreateCommand {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
if (cipher.organizationId == null && !(await this.stateService.getCanAccessPremium())) {
|
||||
if (
|
||||
cipher.organizationId == null &&
|
||||
!(await firstValueFrom(this.accountProfileService.hasPremiumFromAnySource$))
|
||||
) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
@@ -12,9 +14,9 @@ export class DeleteCommand {
|
||||
constructor(
|
||||
private cipherService: CipherService,
|
||||
private folderService: FolderService,
|
||||
private stateService: StateService,
|
||||
private apiService: ApiService,
|
||||
private folderApiService: FolderApiServiceAbstraction,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
@@ -75,7 +77,10 @@ export class DeleteCommand {
|
||||
return Response.error("Attachment `" + id + "` was not found.");
|
||||
}
|
||||
|
||||
if (cipher.organizationId == null && !(await this.stateService.getCanAccessPremium())) {
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.accountProfileService.hasPremiumFromAnySource$,
|
||||
);
|
||||
if (cipher.organizationId == null && !canAccessPremium) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user