1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-02-13 00:51:45 +01:00

Merge branch 'main' into autofill/pm-6546-blurring-of-autofilled-elements-causes-problems-in-blur-event-listeners

This commit is contained in:
Cesar Gonzalez 2024-03-19 10:55:52 -05:00 committed by GitHub
commit 57464c41f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
222 changed files with 7097 additions and 1676 deletions

72
.github/workflows/scan.yml vendored Normal file
View File

@ -0,0 +1,72 @@
name: Scan
on:
workflow_dispatch:
push:
branches:
- "main"
- "rc"
- "hotfix-rc"
pull_request_target:
types: [opened, synchronize]
permissions: read-all
jobs:
check-run:
name: Check PR run
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
sast:
name: SAST scan
runs-on: ubuntu-22.04
needs: check-run
permissions:
security-events: write
steps:
- name: Check out repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Scan with Checkmarx
uses: checkmarx/ast-github-action@749fec53e0db0f6404a97e2e0807c3e80e3583a7 #2.0.23
env:
INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
with:
project_name: ${{ github.repository }}
cx_tenant: ${{ secrets.CHECKMARX_TENANT }}
base_uri: https://ast.checkmarx.net/
cx_client_id: ${{ secrets.CHECKMARX_CLIENT_ID }}
cx_client_secret: ${{ secrets.CHECKMARX_SECRET }}
additional_params: --report-format sarif --output-path . ${{ env.INCREMENTAL }}
- name: Upload Checkmarx results to GitHub
uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
with:
sarif_file: cx_result.sarif
quality:
name: Quality scan
runs-on: ubuntu-22.04
needs: check-run
steps:
- name: Check out repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Scan with SonarCloud
uses: sonarsource/sonarcloud-github-action@49e6cd3b187936a73b8280d59ffd9da69df63ec9 # v2.1.1
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: >
-Dsonar.organization=${{ github.repository_owner }}
-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}
-Dsonar.test.inclusions=**/*.spec.ts
-Dsonar.tests=.

View File

@ -1,4 +1,5 @@
import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
import { import {
FactoryOptions, FactoryOptions,
@ -6,11 +7,7 @@ import {
factory, factory,
} from "../../../platform/background/service-factories/factory-options"; } from "../../../platform/background/service-factories/factory-options";
import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory"; import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory";
import { import { StateServiceInitOptions } from "../../../platform/background/service-factories/state-service.factory";
stateServiceFactory,
StateServiceInitOptions,
} from "../../../platform/background/service-factories/state-service.factory";
import { BrowserOrganizationService } from "../../services/browser-organization.service";
type OrganizationServiceFactoryOptions = FactoryOptions; type OrganizationServiceFactoryOptions = FactoryOptions;
@ -25,10 +22,6 @@ export function organizationServiceFactory(
cache, cache,
"organizationService", "organizationService",
opts, opts,
async () => async () => new OrganizationService(await stateProviderFactory(cache, opts)),
new BrowserOrganizationService(
await stateServiceFactory(cache, opts),
await stateProviderFactory(cache, opts),
),
); );
} }

View File

@ -1,12 +0,0 @@
import { BehaviorSubject } from "rxjs";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
import { browserSession, sessionSync } from "../../platform/decorators/session-sync-observable";
@browserSession
export class BrowserOrganizationService extends OrganizationService {
@sessionSync({ initializer: Organization.fromJSON, initializeAs: "array" })
protected _organizations: BehaviorSubject<Organization[]>;
}

View File

@ -9,6 +9,7 @@ import {
ApiServiceInitOptions, ApiServiceInitOptions,
} from "../../../platform/background/service-factories/api-service.factory"; } from "../../../platform/background/service-factories/api-service.factory";
import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory"; import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory";
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
import { import {
CryptoServiceInitOptions, CryptoServiceInitOptions,
cryptoServiceFactory, cryptoServiceFactory,
@ -119,6 +120,7 @@ export function loginStrategyServiceFactory(
await deviceTrustCryptoServiceFactory(cache, opts), await deviceTrustCryptoServiceFactory(cache, opts),
await authRequestServiceFactory(cache, opts), await authRequestServiceFactory(cache, opts),
await globalStateProviderFactory(cache, opts), await globalStateProviderFactory(cache, opts),
await billingAccountProfileStateServiceFactory(cache, opts),
), ),
); );
} }

View File

@ -7,13 +7,29 @@ import {
factory, factory,
} from "../../../platform/background/service-factories/factory-options"; } from "../../../platform/background/service-factories/factory-options";
import { import {
stateServiceFactory, GlobalStateProviderInitOptions,
StateServiceInitOptions, globalStateProviderFactory,
} from "../../../platform/background/service-factories/state-service.factory"; } from "../../../platform/background/service-factories/global-state-provider.factory";
import {
PlatformUtilsServiceInitOptions,
platformUtilsServiceFactory,
} from "../../../platform/background/service-factories/platform-utils-service.factory";
import {
SingleUserStateProviderInitOptions,
singleUserStateProviderFactory,
} from "../../../platform/background/service-factories/single-user-state-provider.factory";
import {
SecureStorageServiceInitOptions,
secureStorageServiceFactory,
} from "../../../platform/background/service-factories/storage-service.factory";
type TokenServiceFactoryOptions = FactoryOptions; type TokenServiceFactoryOptions = FactoryOptions;
export type TokenServiceInitOptions = TokenServiceFactoryOptions & StateServiceInitOptions; export type TokenServiceInitOptions = TokenServiceFactoryOptions &
SingleUserStateProviderInitOptions &
GlobalStateProviderInitOptions &
PlatformUtilsServiceInitOptions &
SecureStorageServiceInitOptions;
export function tokenServiceFactory( export function tokenServiceFactory(
cache: { tokenService?: AbstractTokenService } & CachedServices, cache: { tokenService?: AbstractTokenService } & CachedServices,
@ -23,6 +39,12 @@ export function tokenServiceFactory(
cache, cache,
"tokenService", "tokenService",
opts, opts,
async () => new TokenService(await stateServiceFactory(cache, opts)), async () =>
new TokenService(
await singleUserStateProviderFactory(cache, opts),
await globalStateProviderFactory(cache, opts),
(await platformUtilsServiceFactory(cache, opts)).supportsSecureStorage(),
await secureStorageServiceFactory(cache, opts),
),
); );
} }

View File

@ -91,6 +91,8 @@ export class LoginComponent extends BaseLoginComponent {
} }
async launchSsoBrowser() { async launchSsoBrowser() {
// Save off email for SSO
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
await this.loginService.saveEmailSettings(); await this.loginService.saveEmailSettings();
// Generate necessary sso params // Generate necessary sso params
const passwordOptions: any = { const passwordOptions: any = {

View File

@ -8,11 +8,21 @@ import {
AutofillOverlayVisibility, AutofillOverlayVisibility,
} from "@bitwarden/common/autofill/constants"; } from "@bitwarden/common/autofill/constants";
import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service"; 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 { ThemeType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
import { I18nService } from "@bitwarden/common/platform/services/i18n.service"; import { I18nService } from "@bitwarden/common/platform/services/i18n.service";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.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 { CipherType } from "@bitwarden/common/vault/enums";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; 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/"; const iconServerUrl = "https://icons.bitwarden.com/";
describe("OverlayBackground", () => { 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 buttonPortSpy: chrome.runtime.Port;
let listPortSpy: chrome.runtime.Port; let listPortSpy: chrome.runtime.Port;
let overlayBackground: OverlayBackground; let overlayBackground: OverlayBackground;
@ -50,7 +64,6 @@ describe("OverlayBackground", () => {
const environmentService = mock<EnvironmentService>({ const environmentService = mock<EnvironmentService>({
getIconsUrl: () => iconServerUrl, getIconsUrl: () => iconServerUrl,
}); });
const settingsService = mock<SettingsService>();
const stateService = mock<BrowserStateService>(); const stateService = mock<BrowserStateService>();
const autofillSettingsService = mock<AutofillSettingsService>(); const autofillSettingsService = mock<AutofillSettingsService>();
const i18nService = mock<I18nService>(); const i18nService = mock<I18nService>();
@ -72,12 +85,13 @@ describe("OverlayBackground", () => {
}; };
beforeEach(() => { beforeEach(() => {
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
overlayBackground = new OverlayBackground( overlayBackground = new OverlayBackground(
cipherService, cipherService,
autofillService, autofillService,
authService, authService,
environmentService, environmentService,
settingsService, domainSettingsService,
stateService, stateService,
autofillSettingsService, autofillSettingsService,
i18nService, i18nService,
@ -90,6 +104,7 @@ describe("OverlayBackground", () => {
.mockResolvedValue(AutofillOverlayVisibility.OnFieldFocus); .mockResolvedValue(AutofillOverlayVisibility.OnFieldFocus);
themeStateService.selectedTheme$ = of(ThemeType.Light); themeStateService.selectedTheme$ = of(ThemeType.Light);
domainSettingsService.showFavicons$ = of(true);
void overlayBackground.init(); void overlayBackground.init();
}); });
@ -274,7 +289,7 @@ describe("OverlayBackground", () => {
card: { subTitle: "Mastercard, *1234" }, card: { subTitle: "Mastercard, *1234" },
}); });
it("formats and returns the cipher data", () => { it("formats and returns the cipher data", async () => {
overlayBackground["overlayLoginCiphers"] = new Map([ overlayBackground["overlayLoginCiphers"] = new Map([
["overlay-cipher-0", cipher2], ["overlay-cipher-0", cipher2],
["overlay-cipher-1", cipher1], ["overlay-cipher-1", cipher1],
@ -282,7 +297,7 @@ describe("OverlayBackground", () => {
["overlay-cipher-3", cipher4], ["overlay-cipher-3", cipher4],
]); ]);
const overlayCipherData = overlayBackground["getOverlayCipherData"](); const overlayCipherData = await overlayBackground["getOverlayCipherData"]();
expect(overlayCipherData).toStrictEqual([ expect(overlayCipherData).toStrictEqual([
{ {

View File

@ -1,10 +1,10 @@
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { SHOW_AUTOFILL_BUTTON } from "@bitwarden/common/autofill/constants"; import { SHOW_AUTOFILL_BUTTON } from "@bitwarden/common/autofill/constants";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; 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 { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -92,7 +92,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
private autofillService: AutofillService, private autofillService: AutofillService,
private authService: AuthService, private authService: AuthService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private settingsService: SettingsService, private domainSettingsService: DomainSettingsService,
private stateService: StateService, private stateService: StateService,
private autofillSettingsService: AutofillSettingsServiceAbstraction, private autofillSettingsService: AutofillSettingsServiceAbstraction,
private i18nService: I18nService, private i18nService: I18nService,
@ -145,7 +145,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.overlayLoginCiphers.set(`overlay-cipher-${cipherIndex}`, ciphersViews[cipherIndex]); this.overlayLoginCiphers.set(`overlay-cipher-${cipherIndex}`, ciphersViews[cipherIndex]);
} }
const ciphers = this.getOverlayCipherData(); const ciphers = await this.getOverlayCipherData();
this.overlayListPort?.postMessage({ command: "updateOverlayListCiphers", ciphers }); this.overlayListPort?.postMessage({ command: "updateOverlayListCiphers", ciphers });
await BrowserApi.tabSendMessageData(currentTab, "updateIsOverlayCiphersPopulated", { await BrowserApi.tabSendMessageData(currentTab, "updateIsOverlayCiphersPopulated", {
isOverlayCiphersPopulated: Boolean(ciphers.length), isOverlayCiphersPopulated: Boolean(ciphers.length),
@ -156,8 +156,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
* Strips out unnecessary data from the ciphers and returns an array of * Strips out unnecessary data from the ciphers and returns an array of
* objects that contain the cipher data needed for the overlay list. * objects that contain the cipher data needed for the overlay list.
*/ */
private getOverlayCipherData(): OverlayCipherData[] { private async getOverlayCipherData(): Promise<OverlayCipherData[]> {
const isFaviconDisabled = this.settingsService.getDisableFavicon(); const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$);
const overlayCiphersArray = Array.from(this.overlayLoginCiphers); const overlayCiphersArray = Array.from(this.overlayLoginCiphers);
const overlayCipherData = []; const overlayCipherData = [];
let loginCipherIcon: WebsiteIconData; let loginCipherIcon: WebsiteIconData;
@ -165,7 +165,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
for (let cipherIndex = 0; cipherIndex < overlayCiphersArray.length; cipherIndex++) { for (let cipherIndex = 0; cipherIndex < overlayCiphersArray.length; cipherIndex++) {
const [overlayCipherId, cipher] = overlayCiphersArray[cipherIndex]; const [overlayCipherId, cipher] = overlayCiphersArray[cipherIndex];
if (!loginCipherIcon && cipher.type === CipherType.Login) { if (!loginCipherIcon && cipher.type === CipherType.Login) {
loginCipherIcon = buildCipherIcon(this.iconsServerUrl, cipher, isFaviconDisabled); loginCipherIcon = buildCipherIcon(this.iconsServerUrl, cipher, showFavicons);
} }
overlayCipherData.push({ overlayCipherData.push({
@ -177,7 +177,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
icon: icon:
cipher.type === CipherType.Login cipher.type === CipherType.Login
? loginCipherIcon ? loginCipherIcon
: buildCipherIcon(this.iconsServerUrl, cipher, isFaviconDisabled), : buildCipherIcon(this.iconsServerUrl, cipher, showFavicons),
login: cipher.type === CipherType.Login ? { username: cipher.login.username } : null, login: cipher.type === CipherType.Login ? { username: cipher.login.username } : null,
card: cipher.type === CipherType.Card ? cipher.card.subTitle : 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`), styleSheetUrl: chrome.runtime.getURL(`overlay/${isOverlayListPort ? "list" : "button"}.css`),
theme: await firstValueFrom(this.themeStateService.selectedTheme$), theme: await firstValueFrom(this.themeStateService.selectedTheme$),
translations: this.getTranslations(), translations: this.getTranslations(),
ciphers: isOverlayListPort ? this.getOverlayCipherData() : null, ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null,
}); });
this.updateOverlayPosition({ this.updateOverlayPosition({
overlayElement: isOverlayListPort overlayElement: isOverlayListPort

View File

@ -6,6 +6,7 @@ import {
EventCollectionServiceInitOptions, EventCollectionServiceInitOptions,
eventCollectionServiceFactory, eventCollectionServiceFactory,
} from "../../../background/service-factories/event-collection-service.factory"; } from "../../../background/service-factories/event-collection-service.factory";
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
import { import {
CachedServices, CachedServices,
factory, factory,
@ -69,6 +70,7 @@ export function autofillServiceFactory(
await logServiceFactory(cache, opts), await logServiceFactory(cache, opts),
await domainSettingsServiceFactory(cache, opts), await domainSettingsServiceFactory(cache, opts),
await userVerificationServiceFactory(cache, opts), await userVerificationServiceFactory(cache, opts),
await billingAccountProfileStateServiceFactory(cache, opts),
), ),
); );
} }

View File

@ -3,6 +3,7 @@ import { of } from "rxjs";
import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants"; import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.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";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
@ -18,6 +19,7 @@ describe("context-menu", () => {
let autofillSettingsService: MockProxy<AutofillSettingsServiceAbstraction>; let autofillSettingsService: MockProxy<AutofillSettingsServiceAbstraction>;
let i18nService: MockProxy<I18nService>; let i18nService: MockProxy<I18nService>;
let logService: MockProxy<LogService>; let logService: MockProxy<LogService>;
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
let removeAllSpy: jest.SpyInstance<void, [callback?: () => void]>; let removeAllSpy: jest.SpyInstance<void, [callback?: () => void]>;
let createSpy: jest.SpyInstance< let createSpy: jest.SpyInstance<
@ -32,6 +34,7 @@ describe("context-menu", () => {
autofillSettingsService = mock(); autofillSettingsService = mock();
i18nService = mock(); i18nService = mock();
logService = mock(); logService = mock();
billingAccountProfileStateService = mock();
removeAllSpy = jest removeAllSpy = jest
.spyOn(chrome.contextMenus, "removeAll") .spyOn(chrome.contextMenus, "removeAll")
@ -50,6 +53,7 @@ describe("context-menu", () => {
autofillSettingsService, autofillSettingsService,
i18nService, i18nService,
logService, logService,
billingAccountProfileStateService,
); );
autofillSettingsService.enableContextMenu$ = of(true); autofillSettingsService.enableContextMenu$ = of(true);
}); });
@ -66,7 +70,7 @@ describe("context-menu", () => {
}); });
it("has menu enabled, but does not have premium", async () => { it("has menu enabled, but does not have premium", async () => {
stateService.getCanAccessPremium.mockResolvedValue(false); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
const createdMenu = await sut.init(); const createdMenu = await sut.init();
expect(createdMenu).toBeTruthy(); expect(createdMenu).toBeTruthy();
@ -74,7 +78,7 @@ describe("context-menu", () => {
}); });
it("has menu enabled and has premium", async () => { it("has menu enabled and has premium", async () => {
stateService.getCanAccessPremium.mockResolvedValue(true); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
const createdMenu = await sut.init(); const createdMenu = await sut.init();
expect(createdMenu).toBeTruthy(); expect(createdMenu).toBeTruthy();
@ -128,7 +132,7 @@ describe("context-menu", () => {
}); });
it("create entry for each cipher piece", async () => { it("create entry for each cipher piece", async () => {
stateService.getCanAccessPremium.mockResolvedValue(true); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
await sut.loadOptions("TEST_TITLE", "1", createCipher()); await sut.loadOptions("TEST_TITLE", "1", createCipher());
@ -137,7 +141,7 @@ describe("context-menu", () => {
}); });
it("creates a login/unlock item for each context menu action option when user is not authenticated", async () => { it("creates a login/unlock item for each context menu action option when user is not authenticated", async () => {
stateService.getCanAccessPremium.mockResolvedValue(true); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
await sut.loadOptions("TEST_TITLE", "NOOP"); await sut.loadOptions("TEST_TITLE", "NOOP");

View File

@ -17,6 +17,7 @@ import {
SEPARATOR_ID, SEPARATOR_ID,
} from "@bitwarden/common/autofill/constants"; } from "@bitwarden/common/autofill/constants";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.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";
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
@ -27,6 +28,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory"; import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory";
import { Account } from "../../models/account"; import { Account } from "../../models/account";
import { billingAccountProfileStateServiceFactory } from "../../platform/background/service-factories/billing-account-profile-state-service.factory";
import { CachedServices } from "../../platform/background/service-factories/factory-options"; import { CachedServices } from "../../platform/background/service-factories/factory-options";
import { import {
i18nServiceFactory, i18nServiceFactory,
@ -163,6 +165,7 @@ export class MainContextMenuHandler {
private autofillSettingsService: AutofillSettingsServiceAbstraction, private autofillSettingsService: AutofillSettingsServiceAbstraction,
private i18nService: I18nService, private i18nService: I18nService,
private logService: LogService, private logService: LogService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {}
static async mv3Create(cachedServices: CachedServices) { static async mv3Create(cachedServices: CachedServices) {
@ -184,6 +187,11 @@ export class MainContextMenuHandler {
stateServiceOptions: { stateServiceOptions: {
stateFactory: stateFactory, stateFactory: stateFactory,
}, },
platformUtilsServiceOptions: {
clipboardWriteCallback: () => Promise.resolve(),
biometricCallback: () => Promise.resolve(false),
win: self,
},
}; };
return new MainContextMenuHandler( return new MainContextMenuHandler(
@ -191,6 +199,7 @@ export class MainContextMenuHandler {
await autofillSettingsServiceFactory(cachedServices, serviceOptions), await autofillSettingsServiceFactory(cachedServices, serviceOptions),
await i18nServiceFactory(cachedServices, serviceOptions), await i18nServiceFactory(cachedServices, serviceOptions),
await logServiceFactory(cachedServices, serviceOptions), await logServiceFactory(cachedServices, serviceOptions),
await billingAccountProfileStateServiceFactory(cachedServices, serviceOptions),
); );
} }
@ -212,7 +221,10 @@ export class MainContextMenuHandler {
try { try {
for (const options of this.initContextMenuItems) { for (const options of this.initContextMenuItems) {
if (options.checkPremiumAccess && !(await this.stateService.getCanAccessPremium())) { if (
options.checkPremiumAccess &&
!(await firstValueFrom(this.billingAccountProfileStateService.hasPremiumFromAnySource$))
) {
continue; continue;
} }
@ -307,7 +319,9 @@ export class MainContextMenuHandler {
await createChildItem(COPY_USERNAME_ID); await createChildItem(COPY_USERNAME_ID);
} }
const canAccessPremium = await this.stateService.getCanAccessPremium(); const canAccessPremium = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
);
if (canAccessPremium && (!cipher || !Utils.isNullOrEmpty(cipher.login?.totp))) { if (canAccessPremium && (!cipher || !Utils.isNullOrEmpty(cipher.login?.totp))) {
await createChildItem(COPY_VERIFICATION_CODE_ID); await createChildItem(COPY_VERIFICATION_CODE_ID);
} }

View File

@ -8,6 +8,7 @@ import {
DefaultDomainSettingsService, DefaultDomainSettingsService,
DomainSettingsService, DomainSettingsService,
} from "@bitwarden/common/autofill/services/domain-settings.service"; } from "@bitwarden/common/autofill/services/domain-settings.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@ -72,6 +73,7 @@ describe("AutofillService", () => {
const eventCollectionService = mock<EventCollectionService>(); const eventCollectionService = mock<EventCollectionService>();
const logService = mock<LogService>(); const logService = mock<LogService>();
const userVerificationService = mock<UserVerificationService>(); const userVerificationService = mock<UserVerificationService>();
const billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
beforeEach(() => { beforeEach(() => {
autofillService = new AutofillService( autofillService = new AutofillService(
@ -83,6 +85,7 @@ describe("AutofillService", () => {
logService, logService,
domainSettingsService, domainSettingsService,
userVerificationService, userVerificationService,
billingAccountProfileStateService,
); );
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
@ -476,6 +479,7 @@ describe("AutofillService", () => {
it("throws an error if an autofill did not occur for any of the passed pages", async () => { it("throws an error if an autofill did not occur for any of the passed pages", async () => {
autofillOptions.tab.url = "https://a-different-url.com"; autofillOptions.tab.url = "https://a-different-url.com";
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
try { try {
await autofillService.doAutoFill(autofillOptions); await autofillService.doAutoFill(autofillOptions);
@ -487,7 +491,6 @@ describe("AutofillService", () => {
}); });
it("will autofill login data for a page", async () => { it("will autofill login data for a page", async () => {
jest.spyOn(stateService, "getCanAccessPremium");
jest.spyOn(autofillService as any, "generateFillScript"); jest.spyOn(autofillService as any, "generateFillScript");
jest.spyOn(autofillService as any, "generateLoginFillScript"); jest.spyOn(autofillService as any, "generateLoginFillScript");
jest.spyOn(logService, "info"); jest.spyOn(logService, "info");
@ -497,8 +500,6 @@ describe("AutofillService", () => {
const autofillResult = await autofillService.doAutoFill(autofillOptions); const autofillResult = await autofillService.doAutoFill(autofillOptions);
const currentAutofillPageDetails = autofillOptions.pageDetails[0]; const currentAutofillPageDetails = autofillOptions.pageDetails[0];
expect(stateService.getCanAccessPremium).toHaveBeenCalled();
expect(autofillService["getDefaultUriMatchStrategy"]).toHaveBeenCalled();
expect(autofillService["generateFillScript"]).toHaveBeenCalledWith( expect(autofillService["generateFillScript"]).toHaveBeenCalledWith(
currentAutofillPageDetails.details, currentAutofillPageDetails.details,
{ {
@ -660,7 +661,7 @@ describe("AutofillService", () => {
it("returns a TOTP value", async () => { it("returns a TOTP value", async () => {
const totpCode = "123456"; const totpCode = "123456";
autofillOptions.cipher.login.totp = "totp"; autofillOptions.cipher.login.totp = "totp";
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(true); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true); jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true);
jest.spyOn(totpService, "getCode").mockResolvedValue(totpCode); jest.spyOn(totpService, "getCode").mockResolvedValue(totpCode);
@ -673,7 +674,7 @@ describe("AutofillService", () => {
it("does not return a TOTP value if the user does not have premium features", async () => { it("does not return a TOTP value if the user does not have premium features", async () => {
autofillOptions.cipher.login.totp = "totp"; autofillOptions.cipher.login.totp = "totp";
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(false); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true); jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true);
const autofillResult = await autofillService.doAutoFill(autofillOptions); const autofillResult = await autofillService.doAutoFill(autofillOptions);
@ -707,7 +708,7 @@ describe("AutofillService", () => {
it("returns a null value if the user cannot access premium and the organization does not use TOTP", async () => { it("returns a null value if the user cannot access premium and the organization does not use TOTP", async () => {
autofillOptions.cipher.login.totp = "totp"; autofillOptions.cipher.login.totp = "totp";
autofillOptions.cipher.organizationUseTotp = false; autofillOptions.cipher.organizationUseTotp = false;
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValueOnce(false); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
const autofillResult = await autofillService.doAutoFill(autofillOptions); const autofillResult = await autofillService.doAutoFill(autofillOptions);
@ -717,13 +718,12 @@ describe("AutofillService", () => {
it("returns a null value if the user has disabled `auto TOTP copy`", async () => { it("returns a null value if the user has disabled `auto TOTP copy`", async () => {
autofillOptions.cipher.login.totp = "totp"; autofillOptions.cipher.login.totp = "totp";
autofillOptions.cipher.organizationUseTotp = true; autofillOptions.cipher.organizationUseTotp = true;
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(true); billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(false); jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(false);
jest.spyOn(totpService, "getCode"); jest.spyOn(totpService, "getCode");
const autofillResult = await autofillService.doAutoFill(autofillOptions); const autofillResult = await autofillService.doAutoFill(autofillOptions);
expect(stateService.getCanAccessPremium).toHaveBeenCalled();
expect(autofillService.getShouldAutoCopyTotp).toHaveBeenCalled(); expect(autofillService.getShouldAutoCopyTotp).toHaveBeenCalled();
expect(totpService.getCode).not.toHaveBeenCalled(); expect(totpService.getCode).not.toHaveBeenCalled();
expect(autofillResult).toBeNull(); expect(autofillResult).toBeNull();

View File

@ -5,6 +5,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { import {
UriMatchStrategySetting, UriMatchStrategySetting,
@ -55,6 +56,7 @@ export default class AutofillService implements AutofillServiceInterface {
private logService: LogService, private logService: LogService,
private domainSettingsService: DomainSettingsService, private domainSettingsService: DomainSettingsService,
private userVerificationService: UserVerificationService, private userVerificationService: UserVerificationService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {}
/** /**
@ -240,7 +242,9 @@ export default class AutofillService implements AutofillServiceInterface {
let totp: string | null = null; let totp: string | null = null;
const canAccessPremium = await this.stateService.getCanAccessPremium(); const canAccessPremium = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
);
const defaultUriMatch = await this.getDefaultUriMatchStrategy(); const defaultUriMatch = await this.getDefaultUriMatchStrategy();
if (!canAccessPremium) { if (!canAccessPremium) {

View File

@ -14,12 +14,12 @@ import { EventCollectionService as EventCollectionServiceAbstraction } from "@bi
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.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 { 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 { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
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 { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
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";
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service"; import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
@ -64,6 +64,8 @@ import {
UserNotificationSettingsService, UserNotificationSettingsService,
UserNotificationSettingsServiceAbstraction, UserNotificationSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/user-notification-settings.service"; } from "@bitwarden/common/autofill/services/user-notification-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 { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
@ -180,7 +182,6 @@ import {
VaultExportServiceAbstraction, VaultExportServiceAbstraction,
} from "@bitwarden/vault-export-core"; } from "@bitwarden/vault-export-core";
import { BrowserOrganizationService } from "../admin-console/services/browser-organization.service";
import ContextMenusBackground from "../autofill/background/context-menus.background"; import ContextMenusBackground from "../autofill/background/context-menus.background";
import NotificationBackground from "../autofill/background/notification.background"; import NotificationBackground from "../autofill/background/notification.background";
import OverlayBackground from "../autofill/background/overlay.background"; import OverlayBackground from "../autofill/background/overlay.background";
@ -211,7 +212,6 @@ import { BrowserPlatformUtilsService } from "../platform/services/platform-utils
import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider"; import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider";
import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service"; import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service";
import { BrowserSendService } from "../services/browser-send.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 VaultTimeoutService from "../services/vault-timeout/vault-timeout.service";
import FilelessImporterBackground from "../tools/background/fileless-importer.background"; import FilelessImporterBackground from "../tools/background/fileless-importer.background";
import { BrowserFido2UserInterfaceService } from "../vault/fido2/browser-fido2-user-interface.service"; import { BrowserFido2UserInterfaceService } from "../vault/fido2/browser-fido2-user-interface.service";
@ -240,7 +240,6 @@ export default class MainBackground {
appIdService: AppIdServiceAbstraction; appIdService: AppIdServiceAbstraction;
apiService: ApiServiceAbstraction; apiService: ApiServiceAbstraction;
environmentService: BrowserEnvironmentService; environmentService: BrowserEnvironmentService;
settingsService: SettingsServiceAbstraction;
cipherService: CipherServiceAbstraction; cipherService: CipherServiceAbstraction;
folderService: InternalFolderServiceAbstraction; folderService: InternalFolderServiceAbstraction;
collectionService: CollectionServiceAbstraction; collectionService: CollectionServiceAbstraction;
@ -311,6 +310,7 @@ export default class MainBackground {
biometricStateService: BiometricStateService; biometricStateService: BiometricStateService;
stateEventRunnerService: StateEventRunnerService; stateEventRunnerService: StateEventRunnerService;
ssoLoginService: SsoLoginServiceAbstraction; ssoLoginService: SsoLoginServiceAbstraction;
billingAccountProfileStateService: BillingAccountProfileStateService;
onUpdatedRan: boolean; onUpdatedRan: boolean;
onReplacedRan: boolean; onReplacedRan: boolean;
@ -427,6 +427,21 @@ export default class MainBackground {
); );
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider); this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
this.userNotificationSettingsService = new UserNotificationSettingsService(this.stateProvider);
this.platformUtilsService = new BackgroundPlatformUtilsService(
this.messagingService,
(clipboardValue, clearMs) => this.clearClipboard(clipboardValue, clearMs),
async () => this.biometricUnlock(),
self,
);
this.tokenService = new TokenService(
this.singleUserStateProvider,
this.globalStateProvider,
this.platformUtilsService.supportsSecureStorage(),
this.secureStorageService,
);
const migrationRunner = new MigrationRunner( const migrationRunner = new MigrationRunner(
this.storageService, this.storageService,
this.logService, this.logService,
@ -441,15 +456,9 @@ export default class MainBackground {
new StateFactory(GlobalState, Account), new StateFactory(GlobalState, Account),
this.accountService, this.accountService,
this.environmentService, this.environmentService,
this.tokenService,
migrationRunner, migrationRunner,
); );
this.userNotificationSettingsService = new UserNotificationSettingsService(this.stateProvider);
this.platformUtilsService = new BackgroundPlatformUtilsService(
this.messagingService,
(clipboardValue, clearMs) => this.clearClipboard(clipboardValue, clearMs),
async () => this.biometricUnlock(),
self,
);
const themeStateService = new DefaultThemeStateService(this.globalStateProvider); const themeStateService = new DefaultThemeStateService(this.globalStateProvider);
@ -465,17 +474,17 @@ export default class MainBackground {
this.stateProvider, this.stateProvider,
this.biometricStateService, this.biometricStateService,
); );
this.tokenService = new TokenService(this.stateService);
this.appIdService = new AppIdService(this.globalStateProvider); this.appIdService = new AppIdService(this.globalStateProvider);
this.apiService = new ApiService( this.apiService = new ApiService(
this.tokenService, this.tokenService,
this.platformUtilsService, this.platformUtilsService,
this.environmentService, this.environmentService,
this.appIdService, this.appIdService,
this.stateService,
(expired: boolean) => this.logout(expired), (expired: boolean) => this.logout(expired),
); );
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
this.settingsService = new BrowserSettingsService(this.stateService);
this.fileUploadService = new FileUploadService(this.logService); this.fileUploadService = new FileUploadService(this.logService);
this.cipherFileUploadService = new CipherFileUploadService( this.cipherFileUploadService = new CipherFileUploadService(
this.apiService, this.apiService,
@ -489,10 +498,7 @@ export default class MainBackground {
this.stateProvider, this.stateProvider,
); );
this.syncNotifierService = new SyncNotifierService(); this.syncNotifierService = new SyncNotifierService();
this.organizationService = new BrowserOrganizationService( this.organizationService = new OrganizationService(this.stateProvider);
this.stateService,
this.stateProvider,
);
this.policyService = new PolicyService(this.stateProvider, this.organizationService); this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.autofillSettingsService = new AutofillSettingsService( this.autofillSettingsService = new AutofillSettingsService(
this.stateProvider, this.stateProvider,
@ -562,6 +568,10 @@ export default class MainBackground {
this.stateService, this.stateService,
); );
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
this.activeUserStateProvider,
);
this.loginStrategyService = new LoginStrategyService( this.loginStrategyService = new LoginStrategyService(
this.cryptoService, this.cryptoService,
this.apiService, this.apiService,
@ -581,6 +591,7 @@ export default class MainBackground {
this.deviceTrustCryptoService, this.deviceTrustCryptoService,
this.authRequestService, this.authRequestService,
this.globalStateProvider, this.globalStateProvider,
this.billingAccountProfileStateService,
); );
this.ssoLoginService = new SsoLoginService(this.stateProvider); this.ssoLoginService = new SsoLoginService(this.stateProvider);
@ -708,17 +719,20 @@ export default class MainBackground {
this.sendApiService, this.sendApiService,
this.avatarService, this.avatarService,
logoutCallback, logoutCallback,
this.billingAccountProfileStateService,
); );
this.eventUploadService = new EventUploadService( this.eventUploadService = new EventUploadService(
this.apiService, this.apiService,
this.stateService, this.stateProvider,
this.logService, this.logService,
this.accountService,
); );
this.eventCollectionService = new EventCollectionService( this.eventCollectionService = new EventCollectionService(
this.cipherService, this.cipherService,
this.stateService, this.stateProvider,
this.organizationService, this.organizationService,
this.eventUploadService, this.eventUploadService,
this.accountService,
); );
this.totpService = new TotpService(this.cryptoFunctionService, this.logService); this.totpService = new TotpService(this.cryptoFunctionService, this.logService);
@ -731,6 +745,7 @@ export default class MainBackground {
this.logService, this.logService,
this.domainSettingsService, this.domainSettingsService,
this.userVerificationService, this.userVerificationService,
this.billingAccountProfileStateService,
); );
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService); this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
@ -791,7 +806,6 @@ export default class MainBackground {
this.fido2AuthenticatorService, this.fido2AuthenticatorService,
this.configService, this.configService,
this.authService, this.authService,
this.stateService,
this.vaultSettingsService, this.vaultSettingsService,
this.domainSettingsService, this.domainSettingsService,
this.logService, this.logService,
@ -839,7 +853,6 @@ export default class MainBackground {
this.cryptoService, this.cryptoService,
this.cryptoFunctionService, this.cryptoFunctionService,
this.runtimeBackground, this.runtimeBackground,
this.i18nService,
this.messagingService, this.messagingService,
this.appIdService, this.appIdService,
this.platformUtilsService, this.platformUtilsService,
@ -873,7 +886,7 @@ export default class MainBackground {
this.autofillService, this.autofillService,
this.authService, this.authService,
this.environmentService, this.environmentService,
this.settingsService, this.domainSettingsService,
this.stateService, this.stateService,
this.autofillSettingsService, this.autofillSettingsService,
this.i18nService, this.i18nService,
@ -953,6 +966,7 @@ export default class MainBackground {
this.autofillSettingsService, this.autofillSettingsService,
this.i18nService, this.i18nService,
this.logService, this.logService,
this.billingAccountProfileStateService,
); );
this.cipherContextMenuHandler = new CipherContextMenuHandler( this.cipherContextMenuHandler = new CipherContextMenuHandler(
@ -1092,7 +1106,7 @@ export default class MainBackground {
async logout(expired: boolean, userId?: UserId) { async logout(expired: boolean, userId?: UserId) {
userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id; userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id;
await this.eventUploadService.uploadEvents(userId); await this.eventUploadService.uploadEvents(userId as UserId);
await Promise.all([ await Promise.all([
this.syncService.setLastSync(new Date(0), userId), this.syncService.setLastSync(new Date(0), userId),

View File

@ -5,7 +5,6 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.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 { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -75,7 +74,6 @@ export class NativeMessagingBackground {
private cryptoService: CryptoService, private cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private runtimeBackground: RuntimeBackground, private runtimeBackground: RuntimeBackground,
private i18nService: I18nService,
private messagingService: MessagingService, private messagingService: MessagingService,
private appIdService: AppIdService, private appIdService: AppIdService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,

View File

@ -5,15 +5,14 @@ import {
organizationServiceFactory, organizationServiceFactory,
OrganizationServiceInitOptions, OrganizationServiceInitOptions,
} from "../../admin-console/background/service-factories/organization-service.factory"; } from "../../admin-console/background/service-factories/organization-service.factory";
import { accountServiceFactory } from "../../auth/background/service-factories/account-service.factory";
import { import {
FactoryOptions, FactoryOptions,
CachedServices, CachedServices,
factory, factory,
} from "../../platform/background/service-factories/factory-options"; } from "../../platform/background/service-factories/factory-options";
import { import { stateProviderFactory } from "../../platform/background/service-factories/state-provider.factory";
stateServiceFactory, import { StateServiceInitOptions } from "../../platform/background/service-factories/state-service.factory";
StateServiceInitOptions,
} from "../../platform/background/service-factories/state-service.factory";
import { import {
cipherServiceFactory, cipherServiceFactory,
CipherServiceInitOptions, CipherServiceInitOptions,
@ -43,9 +42,10 @@ export function eventCollectionServiceFactory(
async () => async () =>
new EventCollectionService( new EventCollectionService(
await cipherServiceFactory(cache, opts), await cipherServiceFactory(cache, opts),
await stateServiceFactory(cache, opts), await stateProviderFactory(cache, opts),
await organizationServiceFactory(cache, opts), await organizationServiceFactory(cache, opts),
await eventUploadServiceFactory(cache, opts), await eventUploadServiceFactory(cache, opts),
await accountServiceFactory(cache, opts),
), ),
); );
} }

View File

@ -1,6 +1,7 @@
import { EventUploadService as AbstractEventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService as AbstractEventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { accountServiceFactory } from "../../auth/background/service-factories/account-service.factory";
import { import {
ApiServiceInitOptions, ApiServiceInitOptions,
apiServiceFactory, apiServiceFactory,
@ -14,10 +15,8 @@ import {
logServiceFactory, logServiceFactory,
LogServiceInitOptions, LogServiceInitOptions,
} from "../../platform/background/service-factories/log-service.factory"; } from "../../platform/background/service-factories/log-service.factory";
import { import { stateProviderFactory } from "../../platform/background/service-factories/state-provider.factory";
stateServiceFactory, import { StateServiceInitOptions } from "../../platform/background/service-factories/state-service.factory";
StateServiceInitOptions,
} from "../../platform/background/service-factories/state-service.factory";
type EventUploadServiceOptions = FactoryOptions; type EventUploadServiceOptions = FactoryOptions;
@ -37,8 +36,9 @@ export function eventUploadServiceFactory(
async () => async () =>
new EventUploadService( new EventUploadService(
await apiServiceFactory(cache, opts), await apiServiceFactory(cache, opts),
await stateServiceFactory(cache, opts), await stateProviderFactory(cache, opts),
await logServiceFactory(cache, opts), await logServiceFactory(cache, opts),
await accountServiceFactory(cache, opts),
), ),
); );
} }

View File

@ -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<AbstractSettingsService> {
return factory(
cache,
"settingsService",
opts,
async () => new BrowserSettingsService(await stateServiceFactory(cache, opts)),
);
}

View File

@ -20,6 +20,7 @@ import {
PlatformUtilsServiceInitOptions, PlatformUtilsServiceInitOptions,
platformUtilsServiceFactory, platformUtilsServiceFactory,
} from "./platform-utils-service.factory"; } from "./platform-utils-service.factory";
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
type ApiServiceFactoryOptions = FactoryOptions & { type ApiServiceFactoryOptions = FactoryOptions & {
apiServiceOptions: { apiServiceOptions: {
@ -32,7 +33,8 @@ export type ApiServiceInitOptions = ApiServiceFactoryOptions &
TokenServiceInitOptions & TokenServiceInitOptions &
PlatformUtilsServiceInitOptions & PlatformUtilsServiceInitOptions &
EnvironmentServiceInitOptions & EnvironmentServiceInitOptions &
AppIdServiceInitOptions; AppIdServiceInitOptions &
StateServiceInitOptions;
export function apiServiceFactory( export function apiServiceFactory(
cache: { apiService?: AbstractApiService } & CachedServices, cache: { apiService?: AbstractApiService } & CachedServices,
@ -48,6 +50,7 @@ export function apiServiceFactory(
await platformUtilsServiceFactory(cache, opts), await platformUtilsServiceFactory(cache, opts),
await environmentServiceFactory(cache, opts), await environmentServiceFactory(cache, opts),
await appIdServiceFactory(cache, opts), await appIdServiceFactory(cache, opts),
await stateServiceFactory(cache, opts),
opts.apiServiceOptions.logoutCallback, opts.apiServiceOptions.logoutCallback,
opts.apiServiceOptions.customUserAgent, opts.apiServiceOptions.customUserAgent,
), ),

View File

@ -0,0 +1,28 @@
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 { activeUserStateProviderFactory } from "./active-user-state-provider.factory";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import { StateProviderInitOptions } from "./state-provider.factory";
type BillingAccountProfileStateServiceFactoryOptions = FactoryOptions;
export type BillingAccountProfileStateServiceInitOptions =
BillingAccountProfileStateServiceFactoryOptions & StateProviderInitOptions;
export function billingAccountProfileStateServiceFactory(
cache: {
billingAccountProfileStateService?: BillingAccountProfileStateService;
} & CachedServices,
opts: BillingAccountProfileStateServiceInitOptions,
): Promise<BillingAccountProfileStateService> {
return factory(
cache,
"billingAccountProfileStateService",
opts,
async () =>
new DefaultBillingAccountProfileStateService(
await activeUserStateProviderFactory(cache, opts),
),
);
}

View File

@ -5,6 +5,10 @@ import {
accountServiceFactory, accountServiceFactory,
AccountServiceInitOptions, AccountServiceInitOptions,
} from "../../../auth/background/service-factories/account-service.factory"; } from "../../../auth/background/service-factories/account-service.factory";
import {
tokenServiceFactory,
TokenServiceInitOptions,
} from "../../../auth/background/service-factories/token-service.factory";
import { Account } from "../../../models/account"; import { Account } from "../../../models/account";
import { BrowserStateService } from "../../services/browser-state.service"; import { BrowserStateService } from "../../services/browser-state.service";
@ -38,6 +42,7 @@ export type StateServiceInitOptions = StateServiceFactoryOptions &
LogServiceInitOptions & LogServiceInitOptions &
AccountServiceInitOptions & AccountServiceInitOptions &
EnvironmentServiceInitOptions & EnvironmentServiceInitOptions &
TokenServiceInitOptions &
MigrationRunnerInitOptions; MigrationRunnerInitOptions;
export async function stateServiceFactory( export async function stateServiceFactory(
@ -57,6 +62,7 @@ export async function stateServiceFactory(
opts.stateServiceOptions.stateFactory, opts.stateServiceOptions.stateFactory,
await accountServiceFactory(cache, opts), await accountServiceFactory(cache, opts),
await environmentServiceFactory(cache, opts), await environmentServiceFactory(cache, opts),
await tokenServiceFactory(cache, opts),
await migrationRunnerFactory(cache, opts), await migrationRunnerFactory(cache, opts),
opts.stateServiceOptions.useAccountCache, opts.stateServiceOptions.useAccountCache,
), ),

View File

@ -7,6 +7,7 @@ import localeBn from "@angular/common/locales/bn";
import localeBs from "@angular/common/locales/bs"; import localeBs from "@angular/common/locales/bs";
import localeCa from "@angular/common/locales/ca"; import localeCa from "@angular/common/locales/ca";
import localeCs from "@angular/common/locales/cs"; import localeCs from "@angular/common/locales/cs";
import localeCy from "@angular/common/locales/cy";
import localeDa from "@angular/common/locales/da"; import localeDa from "@angular/common/locales/da";
import localeDe from "@angular/common/locales/de"; import localeDe from "@angular/common/locales/de";
import localeEl from "@angular/common/locales/el"; import localeEl from "@angular/common/locales/el";
@ -19,6 +20,7 @@ import localeFa from "@angular/common/locales/fa";
import localeFi from "@angular/common/locales/fi"; import localeFi from "@angular/common/locales/fi";
import localeFil from "@angular/common/locales/fil"; import localeFil from "@angular/common/locales/fil";
import localeFr from "@angular/common/locales/fr"; import localeFr from "@angular/common/locales/fr";
import localeGl from "@angular/common/locales/gl";
import localeHe from "@angular/common/locales/he"; import localeHe from "@angular/common/locales/he";
import localeHi from "@angular/common/locales/hi"; import localeHi from "@angular/common/locales/hi";
import localeHr from "@angular/common/locales/hr"; import localeHr from "@angular/common/locales/hr";
@ -33,9 +35,13 @@ import localeKo from "@angular/common/locales/ko";
import localeLt from "@angular/common/locales/lt"; import localeLt from "@angular/common/locales/lt";
import localeLv from "@angular/common/locales/lv"; import localeLv from "@angular/common/locales/lv";
import localeMl from "@angular/common/locales/ml"; import localeMl from "@angular/common/locales/ml";
import localeMr from "@angular/common/locales/mr";
import localeMy from "@angular/common/locales/my";
import localeNb from "@angular/common/locales/nb"; import localeNb from "@angular/common/locales/nb";
import localeNe from "@angular/common/locales/ne";
import localeNl from "@angular/common/locales/nl"; import localeNl from "@angular/common/locales/nl";
import localeNn from "@angular/common/locales/nn"; import localeNn from "@angular/common/locales/nn";
import localeOr from "@angular/common/locales/or";
import localePl from "@angular/common/locales/pl"; import localePl from "@angular/common/locales/pl";
import localePtBr from "@angular/common/locales/pt"; import localePtBr from "@angular/common/locales/pt";
import localePtPt from "@angular/common/locales/pt-PT"; import localePtPt from "@angular/common/locales/pt-PT";
@ -46,6 +52,7 @@ import localeSk from "@angular/common/locales/sk";
import localeSl from "@angular/common/locales/sl"; import localeSl from "@angular/common/locales/sl";
import localeSr from "@angular/common/locales/sr"; import localeSr from "@angular/common/locales/sr";
import localeSv from "@angular/common/locales/sv"; import localeSv from "@angular/common/locales/sv";
import localeTe from "@angular/common/locales/te";
import localeTh from "@angular/common/locales/th"; import localeTh from "@angular/common/locales/th";
import localeTr from "@angular/common/locales/tr"; import localeTr from "@angular/common/locales/tr";
import localeUk from "@angular/common/locales/uk"; import localeUk from "@angular/common/locales/uk";
@ -61,6 +68,7 @@ registerLocaleData(localeBn, "bn");
registerLocaleData(localeBs, "bs"); registerLocaleData(localeBs, "bs");
registerLocaleData(localeCa, "ca"); registerLocaleData(localeCa, "ca");
registerLocaleData(localeCs, "cs"); registerLocaleData(localeCs, "cs");
registerLocaleData(localeCy, "cy");
registerLocaleData(localeDa, "da"); registerLocaleData(localeDa, "da");
registerLocaleData(localeDe, "de"); registerLocaleData(localeDe, "de");
registerLocaleData(localeEl, "el"); registerLocaleData(localeEl, "el");
@ -73,6 +81,7 @@ registerLocaleData(localeFa, "fa");
registerLocaleData(localeFi, "fi"); registerLocaleData(localeFi, "fi");
registerLocaleData(localeFil, "fil"); registerLocaleData(localeFil, "fil");
registerLocaleData(localeFr, "fr"); registerLocaleData(localeFr, "fr");
registerLocaleData(localeGl, "gl");
registerLocaleData(localeHe, "he"); registerLocaleData(localeHe, "he");
registerLocaleData(localeHi, "hi"); registerLocaleData(localeHi, "hi");
registerLocaleData(localeHr, "hr"); registerLocaleData(localeHr, "hr");
@ -87,9 +96,13 @@ registerLocaleData(localeKo, "ko");
registerLocaleData(localeLt, "lt"); registerLocaleData(localeLt, "lt");
registerLocaleData(localeLv, "lv"); registerLocaleData(localeLv, "lv");
registerLocaleData(localeMl, "ml"); registerLocaleData(localeMl, "ml");
registerLocaleData(localeMr, "mr");
registerLocaleData(localeMy, "my");
registerLocaleData(localeNb, "nb"); registerLocaleData(localeNb, "nb");
registerLocaleData(localeNe, "ne");
registerLocaleData(localeNl, "nl"); registerLocaleData(localeNl, "nl");
registerLocaleData(localeNn, "nn"); registerLocaleData(localeNn, "nn");
registerLocaleData(localeOr, "or");
registerLocaleData(localePl, "pl"); registerLocaleData(localePl, "pl");
registerLocaleData(localePtBr, "pt-BR"); registerLocaleData(localePtBr, "pt-BR");
registerLocaleData(localePtPt, "pt-PT"); registerLocaleData(localePtPt, "pt-PT");
@ -100,6 +113,7 @@ registerLocaleData(localeSk, "sk");
registerLocaleData(localeSl, "sl"); registerLocaleData(localeSl, "sl");
registerLocaleData(localeSr, "sr"); registerLocaleData(localeSr, "sr");
registerLocaleData(localeSv, "sv"); registerLocaleData(localeSv, "sv");
registerLocaleData(localeTe, "te");
registerLocaleData(localeTh, "th"); registerLocaleData(localeTh, "th");
registerLocaleData(localeTr, "tr"); registerLocaleData(localeTr, "tr");
registerLocaleData(localeUk, "uk"); registerLocaleData(localeUk, "uk");

View File

@ -1,5 +1,6 @@
import { mock, MockProxy } from "jest-mock-extended"; import { mock, MockProxy } from "jest-mock-extended";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { import {
@ -32,6 +33,7 @@ describe("Browser State Service", () => {
let stateFactory: MockProxy<StateFactory<GlobalState, Account>>; let stateFactory: MockProxy<StateFactory<GlobalState, Account>>;
let useAccountCache: boolean; let useAccountCache: boolean;
let environmentService: MockProxy<EnvironmentService>; let environmentService: MockProxy<EnvironmentService>;
let tokenService: MockProxy<TokenService>;
let migrationRunner: MockProxy<MigrationRunner>; let migrationRunner: MockProxy<MigrationRunner>;
let state: State<GlobalState, Account>; let state: State<GlobalState, Account>;
@ -46,6 +48,7 @@ describe("Browser State Service", () => {
logService = mock(); logService = mock();
stateFactory = mock(); stateFactory = mock();
environmentService = mock(); environmentService = mock();
tokenService = mock();
migrationRunner = mock(); migrationRunner = mock();
// turn off account cache for tests // turn off account cache for tests
useAccountCache = false; useAccountCache = false;
@ -77,6 +80,7 @@ describe("Browser State Service", () => {
stateFactory, stateFactory,
accountService, accountService,
environmentService, environmentService,
tokenService,
migrationRunner, migrationRunner,
useAccountCache, useAccountCache,
); );

View File

@ -1,6 +1,7 @@
import { BehaviorSubject } from "rxjs"; import { BehaviorSubject } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { import {
@ -45,6 +46,7 @@ export class BrowserStateService
stateFactory: StateFactory<GlobalState, Account>, stateFactory: StateFactory<GlobalState, Account>,
accountService: AccountService, accountService: AccountService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
tokenService: TokenService,
migrationRunner: MigrationRunner, migrationRunner: MigrationRunner,
useAccountCache = true, useAccountCache = true,
) { ) {
@ -56,6 +58,7 @@ export class BrowserStateService
stateFactory, stateFactory,
accountService, accountService,
environmentService, environmentService,
tokenService,
migrationRunner, migrationRunner,
useAccountCache, useAccountCache,
); );

View File

@ -17,11 +17,8 @@ import {
LoginStrategyServiceAbstraction, LoginStrategyServiceAbstraction,
} from "@bitwarden/auth/common"; } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.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 { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@ -42,6 +39,10 @@ import {
AutofillSettingsService, AutofillSettingsService,
AutofillSettingsServiceAbstraction, AutofillSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/autofill-settings.service"; } from "@bitwarden/common/autofill/services/autofill-settings.service";
import {
DefaultDomainSettingsService,
DomainSettingsService,
} from "@bitwarden/common/autofill/services/domain-settings.service";
import { import {
UserNotificationSettingsService, UserNotificationSettingsService,
UserNotificationSettingsServiceAbstraction, UserNotificationSettingsServiceAbstraction,
@ -98,7 +99,6 @@ import { DialogService } from "@bitwarden/components";
import { ImportServiceAbstraction } from "@bitwarden/importer/core"; import { ImportServiceAbstraction } from "@bitwarden/importer/core";
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core"; import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
import { BrowserOrganizationService } from "../../admin-console/services/browser-organization.service";
import { UnauthGuardService } from "../../auth/popup/services"; import { UnauthGuardService } from "../../auth/popup/services";
import { AutofillService } from "../../autofill/services/abstractions/autofill.service"; import { AutofillService } from "../../autofill/services/abstractions/autofill.service";
import MainBackground from "../../background/main.background"; import MainBackground from "../../background/main.background";
@ -118,7 +118,6 @@ import { ForegroundPlatformUtilsService } from "../../platform/services/platform
import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider"; import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider";
import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service";
import { BrowserSendService } from "../../services/browser-send.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 { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service";
import { VaultFilterService } from "../../vault/services/vault-filter.service"; import { VaultFilterService } from "../../vault/services/vault-filter.service";
@ -233,7 +232,6 @@ function getBgService<T>(service: keyof MainBackground) {
deps: [], deps: [],
}, },
{ provide: TotpService, useFactory: getBgService<TotpService>("totpService"), deps: [] }, { provide: TotpService, useFactory: getBgService<TotpService>("totpService"), deps: [] },
{ provide: TokenService, useFactory: getBgService<TokenService>("tokenService"), deps: [] },
{ {
provide: I18nServiceAbstraction, provide: I18nServiceAbstraction,
useFactory: (globalStateProvider: GlobalStateProvider) => { useFactory: (globalStateProvider: GlobalStateProvider) => {
@ -265,16 +263,6 @@ function getBgService<T>(service: keyof MainBackground) {
useFactory: getBgService<DevicesServiceAbstraction>("devicesService"), useFactory: getBgService<DevicesServiceAbstraction>("devicesService"),
deps: [], deps: [],
}, },
{
provide: EventUploadService,
useFactory: getBgService<EventUploadService>("eventUploadService"),
deps: [],
},
{
provide: EventCollectionService,
useFactory: getBgService<EventCollectionService>("eventCollectionService"),
deps: [],
},
{ {
provide: PlatformUtilsService, provide: PlatformUtilsService,
useExisting: ForegroundPlatformUtilsService, useExisting: ForegroundPlatformUtilsService,
@ -348,11 +336,9 @@ function getBgService<T>(service: keyof MainBackground) {
}, },
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] }, { provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
{ {
provide: SettingsService, provide: DomainSettingsService,
useFactory: (stateService: StateServiceAbstraction) => { useClass: DefaultDomainSettingsService,
return new BrowserSettingsService(stateService); deps: [StateProvider],
},
deps: [StateServiceAbstraction],
}, },
{ {
provide: AbstractStorageService, provide: AbstractStorageService,
@ -399,13 +385,6 @@ function getBgService<T>(service: keyof MainBackground) {
useFactory: getBgService<NotificationsService>("notificationsService"), useFactory: getBgService<NotificationsService>("notificationsService"),
deps: [], deps: [],
}, },
{
provide: OrganizationService,
useFactory: (stateService: StateServiceAbstraction, stateProvider: StateProvider) => {
return new BrowserOrganizationService(stateService, stateProvider);
},
deps: [StateServiceAbstraction, StateProvider],
},
{ {
provide: VaultFilterService, provide: VaultFilterService,
useClass: VaultFilterService, useClass: VaultFilterService,
@ -445,6 +424,7 @@ function getBgService<T>(service: keyof MainBackground) {
logService: LogServiceAbstraction, logService: LogServiceAbstraction,
accountService: AccountServiceAbstraction, accountService: AccountServiceAbstraction,
environmentService: EnvironmentService, environmentService: EnvironmentService,
tokenService: TokenService,
migrationRunner: MigrationRunner, migrationRunner: MigrationRunner,
) => { ) => {
return new BrowserStateService( return new BrowserStateService(
@ -455,6 +435,7 @@ function getBgService<T>(service: keyof MainBackground) {
new StateFactory(GlobalState, Account), new StateFactory(GlobalState, Account),
accountService, accountService,
environmentService, environmentService,
tokenService,
migrationRunner, migrationRunner,
); );
}, },
@ -465,6 +446,7 @@ function getBgService<T>(service: keyof MainBackground) {
LogServiceAbstraction, LogServiceAbstraction,
AccountServiceAbstraction, AccountServiceAbstraction,
EnvironmentService, EnvironmentService,
TokenService,
MigrationRunner, MigrationRunner,
], ],
}, },

View File

@ -6,7 +6,6 @@ import { DomainSettingsService } from "@bitwarden/common/autofill/services/domai
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.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 { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { BrowserApi } from "../../platform/browser/browser-api"; import { BrowserApi } from "../../platform/browser/browser-api";
@ -31,7 +30,6 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
accountSwitcherEnabled = false; accountSwitcherEnabled = false;
constructor( constructor(
private stateService: StateService,
private domainSettingsService: DomainSettingsService, private domainSettingsService: DomainSettingsService,
private i18nService: I18nService, private i18nService: I18nService,
private router: Router, private router: Router,

View File

@ -1,7 +1,6 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
@ -13,7 +12,6 @@ import {
} from "@bitwarden/common/models/domain/domain-service"; } from "@bitwarden/common/models/domain/domain-service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { ThemeType } from "@bitwarden/common/platform/enums"; import { ThemeType } from "@bitwarden/common/platform/enums";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
@ -51,14 +49,12 @@ export class OptionsComponent implements OnInit {
constructor( constructor(
private messagingService: MessagingService, private messagingService: MessagingService,
private stateService: StateService,
private userNotificationSettingsService: UserNotificationSettingsServiceAbstraction, private userNotificationSettingsService: UserNotificationSettingsServiceAbstraction,
private autofillSettingsService: AutofillSettingsServiceAbstraction, private autofillSettingsService: AutofillSettingsServiceAbstraction,
private domainSettingsService: DomainSettingsService, private domainSettingsService: DomainSettingsService,
private badgeSettingsService: BadgeSettingsServiceAbstraction, private badgeSettingsService: BadgeSettingsServiceAbstraction,
i18nService: I18nService, i18nService: I18nService,
private themeStateService: ThemeStateService, private themeStateService: ThemeStateService,
private settingsService: SettingsService,
private vaultSettingsService: VaultSettingsService, private vaultSettingsService: VaultSettingsService,
) { ) {
this.themeOptions = [ this.themeOptions = [
@ -121,7 +117,7 @@ export class OptionsComponent implements OnInit {
this.enableAutoTotpCopy = await firstValueFrom(this.autofillSettingsService.autoCopyTotp$); 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$); this.enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
@ -171,7 +167,7 @@ export class OptionsComponent implements OnInit {
} }
async updateFavicon() { async updateFavicon() {
await this.settingsService.setDisableFavicon(!this.enableFavicon); await this.domainSettingsService.setShowFavicons(this.enableFavicon);
} }
async updateBadgeCounter() { async updateBadgeCounter() {

View File

@ -12,7 +12,7 @@
</header> </header>
<main tabindex="-1"> <main tabindex="-1">
<div class="content"> <div class="content">
<ng-container *ngIf="!isPremium"> <ng-container *ngIf="!(isPremium$ | async)">
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p> <p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
<p>{{ "premiumSignUpAndGet" | i18n }}</p> <p>{{ "premiumSignUpAndGet" | i18n }}</p>
<ul class="bwi-ul"> <ul class="bwi-ul">
@ -61,7 +61,7 @@
></i> ></i>
</button> </button>
</ng-container> </ng-container>
<ng-container *ngIf="isPremium"> <ng-container *ngIf="isPremium$ | async">
<p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p> <p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p>
<p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p> <p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p>
<button type="button" class="btn block primary" (click)="manage()"> <button type="button" class="btn block primary" (click)="manage()">

View File

@ -3,6 +3,7 @@ import { Component } from "@angular/core";
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component"; import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
@ -27,6 +28,7 @@ export class PremiumComponent extends BasePremiumComponent {
private currencyPipe: CurrencyPipe, private currencyPipe: CurrencyPipe,
dialogService: DialogService, dialogService: DialogService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
i18nService, i18nService,
@ -36,6 +38,7 @@ export class PremiumComponent extends BasePremiumComponent {
stateService, stateService,
dialogService, dialogService,
environmentService, environmentService,
billingAccountProfileStateService,
); );
// Support old price string. Can be removed in future once all translations are properly updated. // Support old price string. Can be removed in future once all translations are properly updated.

View File

@ -16,7 +16,6 @@ import {
takeUntil, takeUntil,
} from "rxjs"; } from "rxjs";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { FingerprintDialogComponent } from "@bitwarden/auth/angular"; import { FingerprintDialogComponent } from "@bitwarden/auth/angular";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-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 { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
@ -98,7 +97,6 @@ export class SettingsComponent implements OnInit {
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private stateService: StateService, private stateService: StateService,
private modalService: ModalService,
private userVerificationService: UserVerificationService, private userVerificationService: UserVerificationService,
private dialogService: DialogService, private dialogService: DialogService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,

View File

@ -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<boolean>;
}

View File

@ -6,6 +6,7 @@ import { first } from "rxjs/operators";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component"; import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
@ -49,6 +50,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
dialogService: DialogService, dialogService: DialogService,
formBuilder: FormBuilder, formBuilder: FormBuilder,
private filePopoutUtilsService: FilePopoutUtilsService, private filePopoutUtilsService: FilePopoutUtilsService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
i18nService, i18nService,
@ -63,6 +65,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
sendApiService, sendApiService,
dialogService, dialogService,
formBuilder, formBuilder,
billingAccountProfileStateService,
); );
} }

View File

@ -1,10 +1,11 @@
import { Component, EventEmitter, Input, Output } from "@angular/core"; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { Subject, takeUntil } from "rxjs";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.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 { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
@ -15,7 +16,7 @@ import { PasswordRepromptService } from "@bitwarden/vault";
selector: "app-action-buttons", selector: "app-action-buttons",
templateUrl: "action-buttons.component.html", templateUrl: "action-buttons.component.html",
}) })
export class ActionButtonsComponent { export class ActionButtonsComponent implements OnInit, OnDestroy {
@Output() onView = new EventEmitter<CipherView>(); @Output() onView = new EventEmitter<CipherView>();
@Output() launchEvent = new EventEmitter<CipherView>(); @Output() launchEvent = new EventEmitter<CipherView>();
@Input() cipher: CipherView; @Input() cipher: CipherView;
@ -24,17 +25,28 @@ export class ActionButtonsComponent {
cipherType = CipherType; cipherType = CipherType;
userHasPremiumAccess = false; userHasPremiumAccess = false;
private componentIsDestroyed$ = new Subject<boolean>();
constructor( constructor(
private i18nService: I18nService, private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private eventCollectionService: EventCollectionService, private eventCollectionService: EventCollectionService,
private totpService: TotpService, private totpService: TotpService,
private stateService: StateService,
private passwordRepromptService: PasswordRepromptService, private passwordRepromptService: PasswordRepromptService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {}
async ngOnInit() { ngOnInit() {
this.userHasPremiumAccess = await this.stateService.getCanAccessPremium(); this.billingAccountProfileStateService.hasPremiumFromAnySource$
.pipe(takeUntil(this.componentIsDestroyed$))
.subscribe((canAccessPremium: boolean) => {
this.userHasPremiumAccess = canAccessPremium;
});
}
ngOnDestroy() {
this.componentIsDestroyed$.next(true);
this.componentIsDestroyed$.complete();
} }
launchCipher() { launchCipher() {

View File

@ -6,7 +6,6 @@ import { firstValueFrom } from "rxjs";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.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 { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { BrowserFido2UserInterfaceSession } from "../../../fido2/browser-fido2-user-interface.service"; import { BrowserFido2UserInterfaceSession } from "../../../fido2/browser-fido2-user-interface.service";
@ -52,7 +51,6 @@ export class Fido2UseBrowserLinkComponent {
protected fido2PopoutSessionData$ = fido2PopoutSessionData$(); protected fido2PopoutSessionData$ = fido2PopoutSessionData$();
constructor( constructor(
private stateService: StateService,
private domainSettingsService: DomainSettingsService, private domainSettingsService: DomainSettingsService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService, private i18nService: I18nService,

View File

@ -5,6 +5,7 @@ import { first } from "rxjs/operators";
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component"; import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -34,6 +35,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
logService: LogService, logService: LogService,
fileDownloadService: FileDownloadService, fileDownloadService: FileDownloadService,
dialogService: DialogService, dialogService: DialogService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -46,6 +48,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
stateService, stateService,
fileDownloadService, fileDownloadService,
dialogService, dialogService,
billingAccountProfileStateService,
); );
} }

View File

@ -275,7 +275,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
const dontShowIdentities = !(await firstValueFrom( const dontShowIdentities = !(await firstValueFrom(
this.vaultSettingsService.showIdentitiesCurrentTab$, this.vaultSettingsService.showIdentitiesCurrentTab$,
)); ));
this.showOrganizations = this.organizationService.hasOrganizations(); this.showOrganizations = await this.organizationService.hasOrganizations();
if (!dontShowCards) { if (!dontShowCards) {
otherTypes.push(CipherType.Card); otherTypes.push(CipherType.Card);
} }

View File

@ -74,7 +74,7 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn
async ngOnInit() { async ngOnInit() {
this.searchTypeSearch = !this.platformUtilsService.isSafari(); this.searchTypeSearch = !this.platformUtilsService.isSafari();
this.showOrganizations = this.organizationService.hasOrganizations(); this.showOrganizations = await this.organizationService.hasOrganizations();
this.vaultFilter = this.vaultFilterService.getVaultFilter(); this.vaultFilter = this.vaultFilterService.getVaultFilter();
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (params) => { this.route.queryParams.pipe(first()).subscribe(async (params) => {

View File

@ -9,6 +9,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
@ -95,6 +96,7 @@ export class ViewComponent extends BaseViewComponent {
fileDownloadService: FileDownloadService, fileDownloadService: FileDownloadService,
dialogService: DialogService, dialogService: DialogService,
datePipe: DatePipe, datePipe: DatePipe,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -117,6 +119,7 @@ export class ViewComponent extends BaseViewComponent {
fileDownloadService, fileDownloadService,
dialogService, dialogService,
datePipe, datePipe,
billingAccountProfileStateService,
); );
} }

View File

@ -203,6 +203,7 @@ export class LoginCommand {
ssoCodeVerifier, ssoCodeVerifier,
this.ssoRedirectUri, this.ssoRedirectUri,
orgIdentifier, orgIdentifier,
undefined, // email to look up 2FA token not required as CLI can't remember 2FA token
twoFactor, twoFactor,
), ),
); );

View File

@ -41,6 +41,8 @@ import {
DefaultDomainSettingsService, DefaultDomainSettingsService,
DomainSettingsService, DomainSettingsService,
} from "@bitwarden/common/autofill/services/domain-settings.service"; } 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 { ClientType } from "@bitwarden/common/enums";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
@ -88,7 +90,6 @@ import { AuditService } from "@bitwarden/common/services/audit.service";
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { SearchService } from "@bitwarden/common/services/search.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 { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service";
import { import {
@ -157,7 +158,6 @@ export class Main {
appIdService: AppIdService; appIdService: AppIdService;
apiService: NodeApiService; apiService: NodeApiService;
environmentService: EnvironmentService; environmentService: EnvironmentService;
settingsService: SettingsService;
cipherService: CipherService; cipherService: CipherService;
folderService: InternalFolderService; folderService: InternalFolderService;
organizationUserService: OrganizationUserService; organizationUserService: OrganizationUserService;
@ -221,6 +221,7 @@ export class Main {
avatarService: AvatarServiceAbstraction; avatarService: AvatarServiceAbstraction;
stateEventRunnerService: StateEventRunnerService; stateEventRunnerService: StateEventRunnerService;
biometricStateService: BiometricStateService; biometricStateService: BiometricStateService;
billingAccountProfileStateService: BillingAccountProfileStateService;
constructor() { constructor() {
let p = null; let p = null;
@ -310,6 +311,13 @@ export class Main {
this.environmentService = new EnvironmentService(this.stateProvider, this.accountService); this.environmentService = new EnvironmentService(this.stateProvider, this.accountService);
this.tokenService = new TokenService(
this.singleUserStateProvider,
this.globalStateProvider,
this.platformUtilsService.supportsSecureStorage(),
this.secureStorageService,
);
const migrationRunner = new MigrationRunner( const migrationRunner = new MigrationRunner(
this.storageService, this.storageService,
this.logService, this.logService,
@ -324,6 +332,7 @@ export class Main {
new StateFactory(GlobalState, Account), new StateFactory(GlobalState, Account),
this.accountService, this.accountService,
this.environmentService, this.environmentService,
this.tokenService,
migrationRunner, migrationRunner,
); );
@ -341,7 +350,6 @@ export class Main {
); );
this.appIdService = new AppIdService(this.globalStateProvider); this.appIdService = new AppIdService(this.globalStateProvider);
this.tokenService = new TokenService(this.stateService);
const customUserAgent = const customUserAgent =
"Bitwarden_CLI/" + "Bitwarden_CLI/" +
@ -354,6 +362,7 @@ export class Main {
this.platformUtilsService, this.platformUtilsService,
this.environmentService, this.environmentService,
this.appIdService, this.appIdService,
this.stateService,
async (expired: boolean) => await this.logout(), async (expired: boolean) => await this.logout(),
customUserAgent, customUserAgent,
); );
@ -364,7 +373,6 @@ export class Main {
this.containerService = new ContainerService(this.cryptoService, this.encryptService); this.containerService = new ContainerService(this.cryptoService, this.encryptService);
this.settingsService = new SettingsService(this.stateService);
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
this.fileUploadService = new FileUploadService(this.logService); this.fileUploadService = new FileUploadService(this.logService);
@ -399,7 +407,7 @@ export class Main {
this.providerService = new ProviderService(this.stateProvider); this.providerService = new ProviderService(this.stateProvider);
this.organizationService = new OrganizationService(this.stateService, this.stateProvider); this.organizationService = new OrganizationService(this.stateProvider);
this.organizationUserService = new OrganizationUserServiceImplementation(this.apiService); this.organizationUserService = new OrganizationUserServiceImplementation(this.apiService);
@ -448,6 +456,10 @@ export class Main {
this.stateService, this.stateService,
); );
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
this.activeUserStateProvider,
);
this.loginStrategyService = new LoginStrategyService( this.loginStrategyService = new LoginStrategyService(
this.cryptoService, this.cryptoService,
this.apiService, this.apiService,
@ -467,6 +479,7 @@ export class Main {
this.deviceTrustCryptoService, this.deviceTrustCryptoService,
this.authRequestService, this.authRequestService,
this.globalStateProvider, this.globalStateProvider,
this.billingAccountProfileStateService,
); );
this.authService = new AuthService( this.authService = new AuthService(
@ -578,6 +591,7 @@ export class Main {
this.sendApiService, this.sendApiService,
this.avatarService, this.avatarService,
async (expired: boolean) => await this.logout(), async (expired: boolean) => await this.logout(),
this.billingAccountProfileStateService,
); );
this.totpService = new TotpService(this.cryptoFunctionService, this.logService); this.totpService = new TotpService(this.cryptoFunctionService, this.logService);
@ -624,15 +638,17 @@ export class Main {
this.eventUploadService = new EventUploadService( this.eventUploadService = new EventUploadService(
this.apiService, this.apiService,
this.stateService, this.stateProvider,
this.logService, this.logService,
this.accountService,
); );
this.eventCollectionService = new EventCollectionService( this.eventCollectionService = new EventCollectionService(
this.cipherService, this.cipherService,
this.stateService, this.stateProvider,
this.organizationService, this.organizationService,
this.eventUploadService, this.eventUploadService,
this.accountService,
); );
} }
@ -656,6 +672,7 @@ export class Main {
}); });
const userId = await this.stateService.getUserId(); const userId = await this.stateService.getUserId();
await Promise.all([ await Promise.all([
this.eventUploadService.uploadEvents(userId as UserId),
this.syncService.setLastSync(new Date(0)), this.syncService.setLastSync(new Date(0)),
this.cryptoService.clearKeys(), this.cryptoService.clearKeys(),
this.cipherService.clear(userId), this.cipherService.clear(userId),

View File

@ -1,9 +1,12 @@
import { firstValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
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 { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { EventType } from "@bitwarden/common/enums";
import { CardExport } from "@bitwarden/common/models/export/card.export"; import { CardExport } from "@bitwarden/common/models/export/card.export";
import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
@ -57,6 +60,7 @@ export class GetCommand extends DownloadCommand {
private apiService: ApiService, private apiService: ApiService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
private eventCollectionService: EventCollectionService, private eventCollectionService: EventCollectionService,
private accountProfileService: BillingAccountProfileStateService,
) { ) {
super(cryptoService); super(cryptoService);
} }
@ -251,7 +255,9 @@ export class GetCommand extends DownloadCommand {
return Response.error("Couldn't generate TOTP code."); return Response.error("Couldn't generate TOTP code.");
} }
const canAccessPremium = await this.stateService.getCanAccessPremium(); const canAccessPremium = await firstValueFrom(
this.accountProfileService.hasPremiumFromAnySource$,
);
if (!canAccessPremium) { if (!canAccessPremium) {
const originalCipher = await this.cipherService.get(cipher.id); const originalCipher = await this.cipherService.get(cipher.id);
if ( if (
@ -334,7 +340,10 @@ export class GetCommand extends DownloadCommand {
return Response.multipleResults(attachments.map((a) => a.id)); 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); const originalCipher = await this.cipherService.get(cipher.id);
if (originalCipher == null || originalCipher.organizationId == null) { if (originalCipher == null || originalCipher.organizationId == null) {
return Response.error("Premium status is required to use this feature."); return Response.error("Premium status is required to use this feature.");

View File

@ -68,6 +68,7 @@ export class ServeCommand {
this.main.apiService, this.main.apiService,
this.main.organizationService, this.main.organizationService,
this.main.eventCollectionService, this.main.eventCollectionService,
this.main.billingAccountProfileStateService,
); );
this.listCommand = new ListCommand( this.listCommand = new ListCommand(
this.main.cipherService, this.main.cipherService,
@ -82,10 +83,10 @@ export class ServeCommand {
this.createCommand = new CreateCommand( this.createCommand = new CreateCommand(
this.main.cipherService, this.main.cipherService,
this.main.folderService, this.main.folderService,
this.main.stateService,
this.main.cryptoService, this.main.cryptoService,
this.main.apiService, this.main.apiService,
this.main.folderApiService, this.main.folderApiService,
this.main.billingAccountProfileStateService,
); );
this.editCommand = new EditCommand( this.editCommand = new EditCommand(
this.main.cipherService, this.main.cipherService,
@ -108,9 +109,9 @@ export class ServeCommand {
this.deleteCommand = new DeleteCommand( this.deleteCommand = new DeleteCommand(
this.main.cipherService, this.main.cipherService,
this.main.folderService, this.main.folderService,
this.main.stateService,
this.main.apiService, this.main.apiService,
this.main.folderApiService, this.main.folderApiService,
this.main.billingAccountProfileStateService,
); );
this.confirmCommand = new ConfirmCommand( this.confirmCommand = new ConfirmCommand(
this.main.apiService, this.main.apiService,
@ -135,9 +136,9 @@ export class ServeCommand {
this.sendCreateCommand = new SendCreateCommand( this.sendCreateCommand = new SendCreateCommand(
this.main.sendService, this.main.sendService,
this.main.stateService,
this.main.environmentService, this.main.environmentService,
this.main.sendApiService, this.main.sendApiService,
this.main.billingAccountProfileStateService,
); );
this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService, this.main.sendApiService); this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService, this.main.sendApiService);
this.sendGetCommand = new SendGetCommand( this.sendGetCommand = new SendGetCommand(
@ -148,9 +149,9 @@ export class ServeCommand {
); );
this.sendEditCommand = new SendEditCommand( this.sendEditCommand = new SendEditCommand(
this.main.sendService, this.main.sendService,
this.main.stateService,
this.sendGetCommand, this.sendGetCommand,
this.main.sendApiService, this.main.sendApiService,
this.main.billingAccountProfileStateService,
); );
this.sendListCommand = new SendListCommand( this.sendListCommand = new SendListCommand(
this.main.sendService, this.main.sendService,

View File

@ -6,6 +6,7 @@ import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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 { ApiService } from "@bitwarden/common/services/api.service"; import { ApiService } from "@bitwarden/common/services/api.service";
(global as any).fetch = fe.default; (global as any).fetch = fe.default;
@ -20,6 +21,7 @@ export class NodeApiService extends ApiService {
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
appIdService: AppIdService, appIdService: AppIdService,
stateService: StateService,
logoutCallback: (expired: boolean) => Promise<void>, logoutCallback: (expired: boolean) => Promise<void>,
customUserAgent: string = null, customUserAgent: string = null,
) { ) {
@ -28,6 +30,7 @@ export class NodeApiService extends ApiService {
platformUtilsService, platformUtilsService,
environmentService, environmentService,
appIdService, appIdService,
stateService,
logoutCallback, logoutCallback,
customUserAgent, customUserAgent,
); );

View File

@ -1,8 +1,10 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; 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 { 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 { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/tools/send/services/send.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 { export class SendCreateCommand {
constructor( constructor(
private sendService: SendService, private sendService: SendService,
private stateService: StateService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private sendApiService: SendApiService, private sendApiService: SendApiService,
private accountProfileService: BillingAccountProfileStateService,
) {} ) {}
async run(requestJson: any, cmdOptions: Record<string, any>) { 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."); return Response.error("Premium status is required to use this feature.");
} }

View File

@ -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 { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/tools/send/services/send.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 { export class SendEditCommand {
constructor( constructor(
private sendService: SendService, private sendService: SendService,
private stateService: StateService,
private getCommand: SendGetCommand, private getCommand: SendGetCommand,
private sendApiService: SendApiService, private sendApiService: SendApiService,
private accountProfileService: BillingAccountProfileStateService,
) {} ) {}
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> { 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"); 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."); return Response.error("Premium status is required to use this feature.");
} }

View File

@ -153,6 +153,7 @@ export class SendProgram extends Program {
this.main.apiService, this.main.apiService,
this.main.organizationService, this.main.organizationService,
this.main.eventCollectionService, this.main.eventCollectionService,
this.main.billingAccountProfileStateService,
); );
const response = await cmd.run("template", object, null); const response = await cmd.run("template", object, null);
this.processResponse(response); this.processResponse(response);
@ -253,9 +254,9 @@ export class SendProgram extends Program {
); );
const cmd = new SendEditCommand( const cmd = new SendEditCommand(
this.main.sendService, this.main.sendService,
this.main.stateService,
getCmd, getCmd,
this.main.sendApiService, this.main.sendApiService,
this.main.billingAccountProfileStateService,
); );
const response = await cmd.run(encodedJson, options); const response = await cmd.run(encodedJson, options);
this.processResponse(response); this.processResponse(response);
@ -323,9 +324,9 @@ export class SendProgram extends Program {
await this.exitIfLocked(); await this.exitIfLocked();
const cmd = new SendCreateCommand( const cmd = new SendCreateCommand(
this.main.sendService, this.main.sendService,
this.main.stateService,
this.main.environmentService, this.main.environmentService,
this.main.sendApiService, this.main.sendApiService,
this.main.billingAccountProfileStateService,
); );
return await cmd.run(encodedJson, options); return await cmd.run(encodedJson, options);
} }

View File

@ -188,6 +188,7 @@ export class VaultProgram extends Program {
this.main.apiService, this.main.apiService,
this.main.organizationService, this.main.organizationService,
this.main.eventCollectionService, this.main.eventCollectionService,
this.main.billingAccountProfileStateService,
); );
const response = await command.run(object, id, cmd); const response = await command.run(object, id, cmd);
this.processResponse(response); this.processResponse(response);
@ -226,10 +227,10 @@ export class VaultProgram extends Program {
const command = new CreateCommand( const command = new CreateCommand(
this.main.cipherService, this.main.cipherService,
this.main.folderService, this.main.folderService,
this.main.stateService,
this.main.cryptoService, this.main.cryptoService,
this.main.apiService, this.main.apiService,
this.main.folderApiService, this.main.folderApiService,
this.main.billingAccountProfileStateService,
); );
const response = await command.run(object, encodedJson, cmd); const response = await command.run(object, encodedJson, cmd);
this.processResponse(response); this.processResponse(response);
@ -313,9 +314,9 @@ export class VaultProgram extends Program {
const command = new DeleteCommand( const command = new DeleteCommand(
this.main.cipherService, this.main.cipherService,
this.main.folderService, this.main.folderService,
this.main.stateService,
this.main.apiService, this.main.apiService,
this.main.folderApiService, this.main.folderApiService,
this.main.billingAccountProfileStateService,
); );
const response = await command.run(object, id, cmd); const response = await command.run(object, id, cmd);
this.processResponse(response); this.processResponse(response);

View File

@ -1,13 +1,15 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { firstValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; 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 { CipherExport } from "@bitwarden/common/models/export/cipher.export";
import { CollectionExport } from "@bitwarden/common/models/export/collection.export"; import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
import { FolderExport } from "@bitwarden/common/models/export/folder.export"; import { FolderExport } from "@bitwarden/common/models/export/folder.export";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; 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 { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
@ -26,10 +28,10 @@ export class CreateCommand {
constructor( constructor(
private cipherService: CipherService, private cipherService: CipherService,
private folderService: FolderService, private folderService: FolderService,
private stateService: StateService,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private apiService: ApiService, private apiService: ApiService,
private folderApiService: FolderApiServiceAbstraction, private folderApiService: FolderApiServiceAbstraction,
private accountProfileService: BillingAccountProfileStateService,
) {} ) {}
async run( async run(
@ -124,7 +126,10 @@ export class CreateCommand {
return Response.notFound(); 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."); return Response.error("Premium status is required to use this feature.");
} }

View File

@ -1,5 +1,7 @@
import { firstValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; 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 { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
@ -12,9 +14,9 @@ export class DeleteCommand {
constructor( constructor(
private cipherService: CipherService, private cipherService: CipherService,
private folderService: FolderService, private folderService: FolderService,
private stateService: StateService,
private apiService: ApiService, private apiService: ApiService,
private folderApiService: FolderApiServiceAbstraction, private folderApiService: FolderApiServiceAbstraction,
private accountProfileService: BillingAccountProfileStateService,
) {} ) {}
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> { 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."); 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."); return Response.error("Premium status is required to use this feature.");
} }

View File

@ -130,12 +130,6 @@ version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]] [[package]]
name = "cbc" name = "cbc"
version = "0.1.2" version = "0.1.2"
@ -333,7 +327,6 @@ dependencies = [
"security-framework-sys", "security-framework-sys",
"sha2", "sha2",
"thiserror", "thiserror",
"tokio",
"typenum", "typenum",
"widestring", "widestring",
"windows", "windows",
@ -377,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.52.0", "windows-sys",
] ]
[[package]] [[package]]
@ -772,17 +765,6 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "mio"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
dependencies = [
"libc",
"wasi",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "napi" name = "napi"
version = "2.13.3" version = "2.13.3"
@ -925,7 +907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.52.0", "windows-sys",
] ]
[[package]] [[package]]
@ -1114,7 +1096,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys 0.52.0", "windows-sys",
] ]
[[package]] [[package]]
@ -1204,15 +1186,6 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -1228,16 +1201,6 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "socket2"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "str-buf" name = "str-buf"
version = "1.0.6" version = "1.0.6"
@ -1295,7 +1258,7 @@ dependencies = [
"fastrand", "fastrand",
"redox_syscall", "redox_syscall",
"rustix", "rustix",
"windows-sys 0.52.0", "windows-sys",
] ]
[[package]] [[package]]
@ -1329,32 +1292,13 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.32.0" version = "1.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes",
"libc",
"mio",
"num_cpus", "num_cpus",
"parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
] ]
[[package]] [[package]]
@ -1606,15 +1550,6 @@ dependencies = [
"windows-targets 0.52.4", "windows-targets 0.52.4",
] ]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"

View File

@ -25,7 +25,6 @@ retry = "=2.0.0"
scopeguard = "=1.2.0" scopeguard = "=1.2.0"
sha2 = "=0.10.8" sha2 = "=0.10.8"
thiserror = "=1.0.51" thiserror = "=1.0.51"
tokio = { version = "=1.32.0", features = ["full"] }
typenum = "=1.17.0" typenum = "=1.17.0"
[build-dependencies] [build-dependencies]

View File

@ -24,7 +24,7 @@
"**/node_modules/argon2/package.json", "**/node_modules/argon2/package.json",
"**/node_modules/argon2/lib/binding/napi-v3/argon2.node" "**/node_modules/argon2/lib/binding/napi-v3/argon2.node"
], ],
"electronVersion": "28.2.6", "electronVersion": "28.2.7",
"generateUpdatesFilesForAllChannels": true, "generateUpdatesFilesForAllChannels": true,
"publish": { "publish": {
"provider": "generic", "provider": "generic",

View File

@ -3,13 +3,12 @@ import { FormBuilder } from "@angular/forms";
import { BehaviorSubject, firstValueFrom, Observable, Subject } from "rxjs"; import { BehaviorSubject, firstValueFrom, Observable, Subject } from "rxjs";
import { concatMap, debounceTime, filter, map, switchMap, takeUntil, tap } from "rxjs/operators"; 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 { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; 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 { 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 { DeviceType } from "@bitwarden/common/enums";
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
@ -115,9 +114,8 @@ export class SettingsComponent implements OnInit {
private autofillSettingsService: AutofillSettingsServiceAbstraction, private autofillSettingsService: AutofillSettingsServiceAbstraction,
private messagingService: MessagingService, private messagingService: MessagingService,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private modalService: ModalService,
private themeStateService: ThemeStateService, private themeStateService: ThemeStateService,
private settingsService: SettingsService, private domainSettingsService: DomainSettingsService,
private dialogService: DialogService, private dialogService: DialogService,
private userVerificationService: UserVerificationServiceAbstraction, private userVerificationService: UserVerificationServiceAbstraction,
private biometricStateService: BiometricStateService, private biometricStateService: BiometricStateService,
@ -251,7 +249,7 @@ export class SettingsComponent implements OnInit {
approveLoginRequests: (await this.stateService.getApproveLoginRequests()) ?? false, approveLoginRequests: (await this.stateService.getApproveLoginRequests()) ?? false,
clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$), clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$),
minimizeOnCopyToClipboard: await this.stateService.getMinimizeOnCopyToClipboard(), minimizeOnCopyToClipboard: await this.stateService.getMinimizeOnCopyToClipboard(),
enableFavicons: !(await this.stateService.getDisableFavicon()), enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$),
enableTray: await this.stateService.getEnableTray(), enableTray: await this.stateService.getEnableTray(),
enableMinToTray: await this.stateService.getEnableMinimizeToTray(), enableMinToTray: await this.stateService.getEnableMinimizeToTray(),
enableCloseToTray: await this.stateService.getEnableCloseToTray(), enableCloseToTray: await this.stateService.getEnableCloseToTray(),
@ -498,7 +496,7 @@ export class SettingsComponent implements OnInit {
} }
async saveFavicons() { async saveFavicons() {
await this.settingsService.setDisableFavicon(!this.form.value.enableFavicons); await this.domainSettingsService.setShowFavicons(this.form.value.enableFavicons);
this.messagingService.send("refreshCiphers"); this.messagingService.send("refreshCiphers");
} }

View File

@ -19,9 +19,9 @@ import { FingerprintDialogComponent } from "@bitwarden/auth/angular";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService } from "@bitwarden/common/abstractions/search.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 { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.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"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
@ -122,7 +122,6 @@ export class AppComponent implements OnInit, OnDestroy {
constructor( constructor(
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private folderService: InternalFolderService, private folderService: InternalFolderService,
private settingsService: SettingsService,
private syncService: SyncService, private syncService: SyncService,
private passwordGenerationService: PasswordGenerationServiceAbstraction, private passwordGenerationService: PasswordGenerationServiceAbstraction,
private cipherService: CipherService, private cipherService: CipherService,
@ -153,6 +152,7 @@ export class AppComponent implements OnInit, OnDestroy {
private biometricStateService: BiometricStateService, private biometricStateService: BiometricStateService,
private stateEventRunnerService: StateEventRunnerService, private stateEventRunnerService: StateEventRunnerService,
private providerService: ProviderService, private providerService: ProviderService,
private organizationService: InternalOrganizationServiceAbstraction,
) {} ) {}
ngOnInit() { ngOnInit() {
@ -574,7 +574,8 @@ export class AppComponent implements OnInit, OnDestroy {
let preLogoutActiveUserId; let preLogoutActiveUserId;
try { try {
await this.eventUploadService.uploadEvents(userBeingLoggedOut); // Provide the userId of the user to upload events for
await this.eventUploadService.uploadEvents(userBeingLoggedOut as UserId);
await this.syncService.setLastSync(new Date(0), userBeingLoggedOut); await this.syncService.setLastSync(new Date(0), userBeingLoggedOut);
await this.cryptoService.clearKeys(userBeingLoggedOut); await this.cryptoService.clearKeys(userBeingLoggedOut);
await this.cipherService.clear(userBeingLoggedOut); await this.cipherService.clear(userBeingLoggedOut);

View File

@ -10,6 +10,7 @@ import {
OBSERVABLE_MEMORY_STORAGE, OBSERVABLE_MEMORY_STORAGE,
OBSERVABLE_DISK_STORAGE, OBSERVABLE_DISK_STORAGE,
WINDOW, WINDOW,
SUPPORTS_SECURE_STORAGE,
SYSTEM_THEME_OBSERVABLE, SYSTEM_THEME_OBSERVABLE,
} from "@bitwarden/angular/services/injection-tokens"; } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
@ -18,6 +19,7 @@ import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/adm
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service"; import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { LoginService } from "@bitwarden/common/auth/services/login.service"; import { LoginService } from "@bitwarden/common/auth/services/login.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
@ -54,7 +56,10 @@ import { LoginGuard } from "../../auth/guards/login.guard";
import { Account } from "../../models/account"; import { Account } from "../../models/account";
import { ElectronCryptoService } from "../../platform/services/electron-crypto.service"; import { ElectronCryptoService } from "../../platform/services/electron-crypto.service";
import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service"; import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service";
import { ElectronPlatformUtilsService } from "../../platform/services/electron-platform-utils.service"; import {
ELECTRON_SUPPORTS_SECURE_STORAGE,
ElectronPlatformUtilsService,
} from "../../platform/services/electron-platform-utils.service";
import { ElectronRendererMessagingService } from "../../platform/services/electron-renderer-messaging.service"; import { ElectronRendererMessagingService } from "../../platform/services/electron-renderer-messaging.service";
import { ElectronRendererSecureStorageService } from "../../platform/services/electron-renderer-secure-storage.service"; import { ElectronRendererSecureStorageService } from "../../platform/services/electron-renderer-secure-storage.service";
import { ElectronRendererStorageService } from "../../platform/services/electron-renderer-storage.service"; import { ElectronRendererStorageService } from "../../platform/services/electron-renderer-storage.service";
@ -101,6 +106,13 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
useClass: ElectronPlatformUtilsService, useClass: ElectronPlatformUtilsService,
deps: [I18nServiceAbstraction, MessagingServiceAbstraction], deps: [I18nServiceAbstraction, MessagingServiceAbstraction],
}, },
{
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
// the TokenService having to inject the PlatformUtilsService which introduces a
// circular dependency on Desktop only.
provide: SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
},
{ {
provide: I18nServiceAbstraction, provide: I18nServiceAbstraction,
useClass: I18nRendererService, useClass: I18nRendererService,
@ -140,6 +152,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
STATE_FACTORY, STATE_FACTORY,
AccountServiceAbstraction, AccountServiceAbstraction,
EnvironmentService, EnvironmentService,
TokenService,
MigrationRunner, MigrationRunner,
STATE_SERVICE_USE_CACHE, STATE_SERVICE_USE_CACHE,
], ],
@ -170,7 +183,6 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
CryptoServiceAbstraction, CryptoServiceAbstraction,
CryptoFunctionServiceAbstraction, CryptoFunctionServiceAbstraction,
MessagingServiceAbstraction, MessagingServiceAbstraction,
I18nServiceAbstraction,
EncryptedMessageHandlerService, EncryptedMessageHandlerService,
DialogService, DialogService,
], ],

View File

@ -4,6 +4,7 @@ import { FormBuilder } from "@angular/forms";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component"; import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
@ -32,6 +33,7 @@ export class AddEditComponent extends BaseAddEditComponent {
sendApiService: SendApiService, sendApiService: SendApiService,
dialogService: DialogService, dialogService: DialogService,
formBuilder: FormBuilder, formBuilder: FormBuilder,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
i18nService, i18nService,
@ -46,6 +48,7 @@ export class AddEditComponent extends BaseAddEditComponent {
sendApiService, sendApiService,
dialogService, dialogService,
formBuilder, formBuilder,
billingAccountProfileStateService,
); );
} }

View File

@ -2,7 +2,9 @@ import * as path from "path";
import { app } from "electron"; import { app } from "electron";
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
import { TokenService } from "@bitwarden/common/auth/services/token.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { DefaultBiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service"; import { DefaultBiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
@ -36,6 +38,7 @@ import { ClipboardMain } from "./platform/main/clipboard.main";
import { DesktopCredentialStorageListener } from "./platform/main/desktop-credential-storage-listener"; import { DesktopCredentialStorageListener } from "./platform/main/desktop-credential-storage-listener";
import { MainCryptoFunctionService } from "./platform/main/main-crypto-function.service"; import { MainCryptoFunctionService } from "./platform/main/main-crypto-function.service";
import { ElectronLogMainService } from "./platform/services/electron-log.main.service"; import { ElectronLogMainService } from "./platform/services/electron-log.main.service";
import { ELECTRON_SUPPORTS_SECURE_STORAGE } from "./platform/services/electron-platform-utils.service";
import { ElectronStateService } from "./platform/services/electron-state.service"; import { ElectronStateService } from "./platform/services/electron-state.service";
import { ElectronStorageService } from "./platform/services/electron-storage.service"; import { ElectronStorageService } from "./platform/services/electron-storage.service";
import { I18nMainService } from "./platform/services/i18n.main.service"; import { I18nMainService } from "./platform/services/i18n.main.service";
@ -53,6 +56,7 @@ export class Main {
mainCryptoFunctionService: MainCryptoFunctionService; mainCryptoFunctionService: MainCryptoFunctionService;
desktopCredentialStorageListener: DesktopCredentialStorageListener; desktopCredentialStorageListener: DesktopCredentialStorageListener;
migrationRunner: MigrationRunner; migrationRunner: MigrationRunner;
tokenService: TokenServiceAbstraction;
windowMain: WindowMain; windowMain: WindowMain;
messagingMain: MessagingMain; messagingMain: MessagingMain;
@ -129,8 +133,13 @@ export class Main {
stateEventRegistrarService, stateEventRegistrarService,
); );
const activeUserStateProvider = new DefaultActiveUserStateProvider(
accountService,
singleUserStateProvider,
);
const stateProvider = new DefaultStateProvider( const stateProvider = new DefaultStateProvider(
new DefaultActiveUserStateProvider(accountService, singleUserStateProvider), activeUserStateProvider,
singleUserStateProvider, singleUserStateProvider,
globalStateProvider, globalStateProvider,
new DefaultDerivedStateProvider(this.memoryStorageForStateProviders), new DefaultDerivedStateProvider(this.memoryStorageForStateProviders),
@ -138,6 +147,13 @@ export class Main {
this.environmentService = new EnvironmentService(stateProvider, accountService); this.environmentService = new EnvironmentService(stateProvider, accountService);
this.tokenService = new TokenService(
singleUserStateProvider,
globalStateProvider,
ELECTRON_SUPPORTS_SECURE_STORAGE,
this.storageService,
);
this.migrationRunner = new MigrationRunner( this.migrationRunner = new MigrationRunner(
this.storageService, this.storageService,
this.logService, this.logService,
@ -155,6 +171,7 @@ export class Main {
new StateFactory(GlobalState, Account), new StateFactory(GlobalState, Account),
accountService, // will not broadcast logouts. This is a hack until we can remove messaging dependency accountService, // will not broadcast logouts. This is a hack until we can remove messaging dependency
this.environmentService, this.environmentService,
this.tokenService,
this.migrationRunner, this.migrationRunner,
false, // Do not use disk caching because this will get out of sync with the renderer service false, // Do not use disk caching because this will get out of sync with the renderer service
); );
@ -176,6 +193,7 @@ export class Main {
this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => { this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => {
this.messagingMain.onMessage(message); this.messagingMain.onMessage(message);
}); });
this.powerMonitorMain = new PowerMonitorMain(this.messagingService); this.powerMonitorMain = new PowerMonitorMain(this.messagingService);
this.menuMain = new MenuMain( this.menuMain = new MenuMain(
this.i18nService, this.i18nService,

View File

@ -8,6 +8,7 @@ import localeBn from "@angular/common/locales/bn";
import localeBs from "@angular/common/locales/bs"; import localeBs from "@angular/common/locales/bs";
import localeCa from "@angular/common/locales/ca"; import localeCa from "@angular/common/locales/ca";
import localeCs from "@angular/common/locales/cs"; import localeCs from "@angular/common/locales/cs";
import localeCy from "@angular/common/locales/cy";
import localeDa from "@angular/common/locales/da"; import localeDa from "@angular/common/locales/da";
import localeDe from "@angular/common/locales/de"; import localeDe from "@angular/common/locales/de";
import localeEl from "@angular/common/locales/el"; import localeEl from "@angular/common/locales/el";
@ -21,6 +22,7 @@ import localeFa from "@angular/common/locales/fa";
import localeFi from "@angular/common/locales/fi"; import localeFi from "@angular/common/locales/fi";
import localeFil from "@angular/common/locales/fil"; import localeFil from "@angular/common/locales/fil";
import localeFr from "@angular/common/locales/fr"; import localeFr from "@angular/common/locales/fr";
import localeGl from "@angular/common/locales/gl";
import localeHe from "@angular/common/locales/he"; import localeHe from "@angular/common/locales/he";
import localeHi from "@angular/common/locales/hi"; import localeHi from "@angular/common/locales/hi";
import localeHr from "@angular/common/locales/hr"; import localeHr from "@angular/common/locales/hr";
@ -32,11 +34,16 @@ import localeKa from "@angular/common/locales/ka";
import localeKm from "@angular/common/locales/km"; import localeKm from "@angular/common/locales/km";
import localeKn from "@angular/common/locales/kn"; import localeKn from "@angular/common/locales/kn";
import localeKo from "@angular/common/locales/ko"; import localeKo from "@angular/common/locales/ko";
import localeLt from "@angular/common/locales/lt";
import localeLv from "@angular/common/locales/lv"; import localeLv from "@angular/common/locales/lv";
import localeMl from "@angular/common/locales/ml"; import localeMl from "@angular/common/locales/ml";
import localeMr from "@angular/common/locales/mr";
import localeMy from "@angular/common/locales/my";
import localeNb from "@angular/common/locales/nb"; import localeNb from "@angular/common/locales/nb";
import localeNe from "@angular/common/locales/ne";
import localeNl from "@angular/common/locales/nl"; import localeNl from "@angular/common/locales/nl";
import localeNn from "@angular/common/locales/nn"; import localeNn from "@angular/common/locales/nn";
import localeOr from "@angular/common/locales/or";
import localePl from "@angular/common/locales/pl"; import localePl from "@angular/common/locales/pl";
import localePtBr from "@angular/common/locales/pt"; import localePtBr from "@angular/common/locales/pt";
import localePtPt from "@angular/common/locales/pt-PT"; import localePtPt from "@angular/common/locales/pt-PT";
@ -48,6 +55,7 @@ import localeSl from "@angular/common/locales/sl";
import localeSr from "@angular/common/locales/sr"; import localeSr from "@angular/common/locales/sr";
import localeMe from "@angular/common/locales/sr-Latn-ME"; import localeMe from "@angular/common/locales/sr-Latn-ME";
import localeSv from "@angular/common/locales/sv"; import localeSv from "@angular/common/locales/sv";
import localeTe from "@angular/common/locales/te";
import localeTh from "@angular/common/locales/th"; import localeTh from "@angular/common/locales/th";
import localeTr from "@angular/common/locales/tr"; import localeTr from "@angular/common/locales/tr";
import localeUk from "@angular/common/locales/uk"; import localeUk from "@angular/common/locales/uk";
@ -64,6 +72,7 @@ registerLocaleData(localeBn, "bn");
registerLocaleData(localeBs, "bs"); registerLocaleData(localeBs, "bs");
registerLocaleData(localeCa, "ca"); registerLocaleData(localeCa, "ca");
registerLocaleData(localeCs, "cs"); registerLocaleData(localeCs, "cs");
registerLocaleData(localeCy, "cy");
registerLocaleData(localeDa, "da"); registerLocaleData(localeDa, "da");
registerLocaleData(localeDe, "de"); registerLocaleData(localeDe, "de");
registerLocaleData(localeEl, "el"); registerLocaleData(localeEl, "el");
@ -77,6 +86,7 @@ registerLocaleData(localeFa, "fa");
registerLocaleData(localeFi, "fi"); registerLocaleData(localeFi, "fi");
registerLocaleData(localeFil, "fil"); registerLocaleData(localeFil, "fil");
registerLocaleData(localeFr, "fr"); registerLocaleData(localeFr, "fr");
registerLocaleData(localeGl, "gl");
registerLocaleData(localeHe, "he"); registerLocaleData(localeHe, "he");
registerLocaleData(localeHi, "hi"); registerLocaleData(localeHi, "hi");
registerLocaleData(localeHr, "hr"); registerLocaleData(localeHr, "hr");
@ -88,12 +98,17 @@ registerLocaleData(localeKa, "ka");
registerLocaleData(localeKm, "km"); registerLocaleData(localeKm, "km");
registerLocaleData(localeKn, "kn"); registerLocaleData(localeKn, "kn");
registerLocaleData(localeKo, "ko"); registerLocaleData(localeKo, "ko");
registerLocaleData(localeLt, "lt");
registerLocaleData(localeLv, "lv"); registerLocaleData(localeLv, "lv");
registerLocaleData(localeMe, "me"); registerLocaleData(localeMe, "me");
registerLocaleData(localeMl, "ml"); registerLocaleData(localeMl, "ml");
registerLocaleData(localeMr, "mr");
registerLocaleData(localeMy, "my");
registerLocaleData(localeNb, "nb"); registerLocaleData(localeNb, "nb");
registerLocaleData(localeNe, "ne");
registerLocaleData(localeNl, "nl"); registerLocaleData(localeNl, "nl");
registerLocaleData(localeNn, "nn"); registerLocaleData(localeNn, "nn");
registerLocaleData(localeOr, "or");
registerLocaleData(localePl, "pl"); registerLocaleData(localePl, "pl");
registerLocaleData(localePtBr, "pt-BR"); registerLocaleData(localePtBr, "pt-BR");
registerLocaleData(localePtPt, "pt-PT"); registerLocaleData(localePtPt, "pt-PT");
@ -104,6 +119,7 @@ registerLocaleData(localeSk, "sk");
registerLocaleData(localeSl, "sl"); registerLocaleData(localeSl, "sl");
registerLocaleData(localeSr, "sr"); registerLocaleData(localeSr, "sr");
registerLocaleData(localeSv, "sv"); registerLocaleData(localeSv, "sv");
registerLocaleData(localeTe, "te");
registerLocaleData(localeTh, "th"); registerLocaleData(localeTh, "th");
registerLocaleData(localeTr, "tr"); registerLocaleData(localeTr, "tr");
registerLocaleData(localeUk, "uk"); registerLocaleData(localeUk, "uk");

View File

@ -8,6 +8,8 @@ import {
import { ClipboardWriteMessage } from "../types/clipboard"; import { ClipboardWriteMessage } from "../types/clipboard";
export const ELECTRON_SUPPORTS_SECURE_STORAGE = true;
export class ElectronPlatformUtilsService implements PlatformUtilsService { export class ElectronPlatformUtilsService implements PlatformUtilsService {
constructor( constructor(
protected i18nService: I18nService, protected i18nService: I18nService,
@ -142,7 +144,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
} }
supportsSecureStorage(): boolean { supportsSecureStorage(): boolean {
return true; return ELECTRON_SUPPORTS_SECURE_STORAGE;
} }
getAutofillKeyboardShortcut(): Promise<string> { getAutofillKeyboardShortcut(): Promise<string> {

View File

@ -4,7 +4,6 @@ import { firstValueFrom } from "rxjs";
import { NativeMessagingVersion } from "@bitwarden/common/enums"; import { NativeMessagingVersion } from "@bitwarden/common/enums";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
@ -33,7 +32,6 @@ export class NativeMessageHandlerService {
private cryptoService: CryptoService, private cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private messagingService: MessagingService, private messagingService: MessagingService,
private i18nService: I18nService,
private encryptedMessageHandlerService: EncryptedMessageHandlerService, private encryptedMessageHandlerService: EncryptedMessageHandlerService,
private dialogService: DialogService, private dialogService: DialogService,
) {} ) {}

View File

@ -3,7 +3,6 @@ import { firstValueFrom } from "rxjs";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.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 { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -35,7 +34,6 @@ export class NativeMessagingService {
private cryptoService: CryptoService, private cryptoService: CryptoService,
private platformUtilService: PlatformUtilsService, private platformUtilService: PlatformUtilsService,
private logService: LogService, private logService: LogService,
private i18nService: I18nService,
private messagingService: MessagingService, private messagingService: MessagingService,
private stateService: StateService, private stateService: StateService,
private biometricStateService: BiometricStateService, private biometricStateService: BiometricStateService,

View File

@ -7,7 +7,7 @@
{{ "premiumMembership" | i18n }} {{ "premiumMembership" | i18n }}
</h1> </h1>
<div class="box-content box-content-padded"> <div class="box-content box-content-padded">
<div *ngIf="!isPremium"> <div *ngIf="!(isPremium$ | async)">
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p> <p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
<p>{{ "premiumSignUpAndGet" | i18n }}</p> <p>{{ "premiumSignUpAndGet" | i18n }}</p>
<ul class="bwi-ul"> <ul class="bwi-ul">
@ -40,7 +40,7 @@
{{ "premiumPrice" | i18n: (price | currency: "$") }} {{ "premiumPrice" | i18n: (price | currency: "$") }}
</p> </p>
</div> </div>
<div *ngIf="isPremium"> <div *ngIf="isPremium$ | async">
<p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p> <p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p>
<p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p> <p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p>
</div> </div>
@ -48,7 +48,7 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="primary" (click)="manage()" *ngIf="isPremium"> <button type="button" class="primary" (click)="manage()" *ngIf="isPremium$ | async">
<b>{{ "premiumManage" | i18n }}</b> <b>{{ "premiumManage" | i18n }}</b>
</button> </button>
<button <button
@ -56,13 +56,13 @@
type="button" type="button"
class="primary" class="primary"
(click)="purchase()" (click)="purchase()"
*ngIf="!isPremium" *ngIf="!(isPremium$ | async)"
[disabled]="$any(purchaseBtn).loading" [disabled]="$any(purchaseBtn).loading"
> >
<b>{{ "premiumPurchase" | i18n }}</b> <b>{{ "premiumPurchase" | i18n }}</b>
</button> </button>
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button> <button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
<div class="right" *ngIf="!isPremium"> <div class="right" *ngIf="!(isPremium$ | async)">
<button <button
#refreshBtn #refreshBtn
type="button" type="button"

View File

@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component"; import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
@ -22,6 +23,7 @@ export class PremiumComponent extends BasePremiumComponent {
stateService: StateService, stateService: StateService,
dialogService: DialogService, dialogService: DialogService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
i18nService, i18nService,
@ -31,6 +33,7 @@ export class PremiumComponent extends BasePremiumComponent {
stateService, stateService,
dialogService, dialogService,
environmentService, environmentService,
billingAccountProfileStateService,
); );
} }
} }

View File

@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component"; import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -26,6 +27,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
stateService: StateService, stateService: StateService,
fileDownloadService: FileDownloadService, fileDownloadService: FileDownloadService,
dialogService: DialogService, dialogService: DialogService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -38,6 +40,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
stateService, stateService,
fileDownloadService, fileDownloadService,
dialogService, dialogService,
billingAccountProfileStateService,
); );
} }
} }

View File

@ -8,6 +8,7 @@ import {
ViewContainerRef, ViewContainerRef,
} from "@angular/core"; } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { first } from "rxjs/operators"; import { first } from "rxjs/operators";
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
@ -15,6 +16,7 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -84,6 +86,7 @@ export class VaultComponent implements OnInit, OnDestroy {
activeFilter: VaultFilter = new VaultFilter(); activeFilter: VaultFilter = new VaultFilter();
private modal: ModalRef = null; private modal: ModalRef = null;
private componentIsDestroyed$ = new Subject<boolean>();
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@ -103,10 +106,16 @@ export class VaultComponent implements OnInit, OnDestroy {
private searchBarService: SearchBarService, private searchBarService: SearchBarService,
private apiService: ApiService, private apiService: ApiService,
private dialogService: DialogService, private dialogService: DialogService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
this.userHasPremiumAccess = await this.stateService.getCanAccessPremium(); this.billingAccountProfileStateService.hasPremiumFromAnySource$
.pipe(takeUntil(this.componentIsDestroyed$))
.subscribe((canAccessPremium: boolean) => {
this.userHasPremiumAccess = canAccessPremium;
});
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
@ -229,6 +238,8 @@ export class VaultComponent implements OnInit, OnDestroy {
ngOnDestroy() { ngOnDestroy() {
this.searchBarService.setEnabled(false); this.searchBarService.setEnabled(false);
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.componentIsDestroyed$.next(true);
this.componentIsDestroyed$.complete();
} }
async load() { async load() {

View File

@ -13,6 +13,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
@ -58,6 +59,7 @@ export class ViewComponent extends BaseViewComponent implements OnChanges {
fileDownloadService: FileDownloadService, fileDownloadService: FileDownloadService,
dialogService: DialogService, dialogService: DialogService,
datePipe: DatePipe, datePipe: DatePipe,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -80,6 +82,7 @@ export class ViewComponent extends BaseViewComponent implements OnChanges {
fileDownloadService, fileDownloadService,
dialogService, dialogService,
datePipe, datePipe,
billingAccountProfileStateService,
); );
} }
ngOnInit() { ngOnInit() {

View File

@ -17,7 +17,7 @@ export class IsPaidOrgGuard implements CanActivate {
) {} ) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const org = this.organizationService.get(route.params.organizationId); const org = await this.organizationService.get(route.params.organizationId);
if (org == null) { if (org == null) {
return this.router.createUrlTree(["/"]); return this.router.createUrlTree(["/"]);

View File

@ -66,7 +66,7 @@ describe("Organization Permissions Guard", () => {
it("permits navigation if no permissions are specified", async () => { it("permits navigation if no permissions are specified", async () => {
const org = orgFactory(); const org = orgFactory();
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);
@ -81,7 +81,7 @@ describe("Organization Permissions Guard", () => {
}; };
const org = orgFactory(); const org = orgFactory();
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);
@ -104,7 +104,7 @@ describe("Organization Permissions Guard", () => {
}); });
const org = orgFactory(); const org = orgFactory();
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);
@ -124,7 +124,7 @@ describe("Organization Permissions Guard", () => {
}), }),
}); });
const org = orgFactory(); const org = orgFactory();
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);
@ -141,7 +141,7 @@ describe("Organization Permissions Guard", () => {
type: OrganizationUserType.Admin, type: OrganizationUserType.Admin,
enabled: false, enabled: false,
}); });
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);
@ -153,7 +153,7 @@ describe("Organization Permissions Guard", () => {
type: OrganizationUserType.Owner, type: OrganizationUserType.Owner,
enabled: false, enabled: false,
}); });
organizationService.get.calledWith(org.id).mockReturnValue(org); organizationService.get.calledWith(org.id).mockResolvedValue(org);
const actual = await organizationPermissionsGuard.canActivate(route, state); const actual = await organizationPermissionsGuard.canActivate(route, state);

View File

@ -28,7 +28,7 @@ export class OrganizationPermissionsGuard implements CanActivate {
await this.syncService.fullSync(false); await this.syncService.fullSync(false);
} }
const org = this.organizationService.get(route.params.organizationId); const org = await this.organizationService.get(route.params.organizationId);
if (org == null) { if (org == null) {
return this.router.createUrlTree(["/"]); return this.router.createUrlTree(["/"]);
} }

View File

@ -16,7 +16,7 @@ export class OrganizationRedirectGuard implements CanActivate {
) {} ) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const org = this.organizationService.get(route.params.organizationId); const org = await this.organizationService.get(route.params.organizationId);
const customRedirect = route.data?.autoRedirectCallback; const customRedirect = route.data?.autoRedirectCallback;
if (customRedirect) { if (customRedirect) {

View File

@ -2,6 +2,7 @@ import { Component, Input } from "@angular/core";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.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 { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { BulkUserDetails } from "./bulk-status.component"; import { BulkUserDetails } from "./bulk-status.component";
@ -14,7 +15,9 @@ export class BulkRemoveComponent {
@Input() organizationId: string; @Input() organizationId: string;
@Input() set users(value: BulkUserDetails[]) { @Input() set users(value: BulkUserDetails[]) {
this._users = value; this._users = value;
this.showNoMasterPasswordWarning = this._users.some((u) => u.hasMasterPassword === false); this.showNoMasterPasswordWarning = this._users.some(
(u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false,
);
} }
get users(): BulkUserDetails[] { get users(): BulkUserDetails[] {

View File

@ -2,6 +2,7 @@ import { DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core"; import { Component, Inject } from "@angular/core";
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 { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
@ -37,7 +38,9 @@ export class BulkRestoreRevokeComponent {
this.isRevoking = data.isRevoking; this.isRevoking = data.isRevoking;
this.organizationId = data.organizationId; this.organizationId = data.organizationId;
this.users = data.users; this.users = data.users;
this.showNoMasterPasswordWarning = this.users.some((u) => u.hasMasterPassword === false); this.showNoMasterPasswordWarning = this.users.some(
(u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false,
);
} }
get bulkTitle() { get bulkTitle() {

View File

@ -35,6 +35,7 @@ import {
PolicyType, PolicyType,
} from "@bitwarden/common/admin-console/enums"; } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
import { ProductType } from "@bitwarden/common/enums"; import { ProductType } from "@bitwarden/common/enums";
import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { ListResponse } from "@bitwarden/common/models/response/list.response";
@ -143,7 +144,7 @@ export class PeopleComponent
async ngOnInit() { async ngOnInit() {
const organization$ = this.route.params.pipe( const organization$ = this.route.params.pipe(
map((params) => this.organizationService.get(params.organizationId)), concatMap((params) => this.organizationService.get$(params.organizationId)),
shareReplay({ refCount: true, bufferSize: 1 }), shareReplay({ refCount: true, bufferSize: 1 }),
); );
@ -155,7 +156,7 @@ export class PeopleComponent
switchMap((organization) => { switchMap((organization) => {
if (organization.isProviderUser) { if (organization.isProviderUser) {
return from(this.policyApiService.getPolicies(organization.id)).pipe( return from(this.policyApiService.getPolicies(organization.id)).pipe(
map((response) => this.policyService.mapPoliciesFromToken(response)), map((response) => Policy.fromListResponse(response)),
); );
} }

View File

@ -1,9 +1,8 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; import { ActivatedRoute, NavigationEnd, Router } from "@angular/router";
import { filter, map, Observable, startWith } from "rxjs"; import { filter, map, Observable, startWith, concatMap } from "rxjs";
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 { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { ReportVariant, reports, ReportType, ReportEntry } from "../../../tools/reports"; import { ReportVariant, reports, ReportType, ReportEntry } from "../../../tools/reports";
@ -17,7 +16,6 @@ export class ReportsHomeComponent implements OnInit {
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private stateService: StateService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
private router: Router, private router: Router,
) {} ) {}
@ -30,7 +28,7 @@ export class ReportsHomeComponent implements OnInit {
); );
this.reports$ = this.route.params.pipe( this.reports$ = this.route.params.pipe(
map((params) => this.organizationService.get(params.organizationId)), concatMap((params) => this.organizationService.get$(params.organizationId)),
map((org) => this.buildReports(org.isFreeOrg)), map((org) => this.buildReports(org.isFreeOrg)),
); );
} }

View File

@ -1,6 +1,6 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { concatMap, takeUntil } from "rxjs"; import { concatMap, takeUntil, map } from "rxjs";
import { tap } from "rxjs/operators"; import { tap } from "rxjs/operators";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
@ -8,8 +8,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { TwoFactorDuoComponent } from "../../../auth/settings/two-factor-duo.component"; import { TwoFactorDuoComponent } from "../../../auth/settings/two-factor-duo.component";
import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../../auth/settings/two-factor-setup.component"; import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../../auth/settings/two-factor-setup.component";
@ -27,18 +27,29 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
messagingService: MessagingService, messagingService: MessagingService,
policyService: PolicyService, policyService: PolicyService,
private route: ActivatedRoute, private route: ActivatedRoute,
stateService: StateService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super(apiService, modalService, messagingService, policyService, stateService); super(
apiService,
modalService,
messagingService,
policyService,
billingAccountProfileStateService,
);
} }
async ngOnInit() { async ngOnInit() {
this.route.params this.route.params
.pipe( .pipe(
tap((params) => { concatMap((params) =>
this.organizationId = params.organizationId; this.organizationService
this.organization = this.organizationService.get(this.organizationId); .get$(params.organizationId)
.pipe(map((organization) => ({ params, organization }))),
),
tap(async (mapResponse) => {
this.organizationId = mapResponse.params.organizationId;
this.organization = mapResponse.organization;
}), }),
concatMap(async () => await super.ngOnInit()), concatMap(async () => await super.ngOnInit()),
takeUntil(this.destroy$), takeUntil(this.destroy$),

View File

@ -9,9 +9,8 @@ import { Subject, switchMap, takeUntil, timer } from "rxjs";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService } from "@bitwarden/common/abstractions/search.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 { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
@ -44,7 +43,6 @@ import {
SingleOrgPolicy, SingleOrgPolicy,
TwoFactorAuthenticationPolicy, TwoFactorAuthenticationPolicy,
} from "./admin-console/organizations/policies"; } from "./admin-console/organizations/policies";
import { RouterService } from "./core";
const BroadcasterSubscriptionId = "AppComponent"; const BroadcasterSubscriptionId = "AppComponent";
const IdleTimeout = 60000 * 10; // 10 minutes const IdleTimeout = 60000 * 10; // 10 minutes
@ -65,7 +63,6 @@ export class AppComponent implements OnDestroy, OnInit {
@Inject(DOCUMENT) private document: Document, @Inject(DOCUMENT) private document: Document,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private folderService: InternalFolderService, private folderService: InternalFolderService,
private settingsService: SettingsService,
private syncService: SyncService, private syncService: SyncService,
private passwordGenerationService: PasswordGenerationServiceAbstraction, private passwordGenerationService: PasswordGenerationServiceAbstraction,
private cipherService: CipherService, private cipherService: CipherService,
@ -81,7 +78,6 @@ export class AppComponent implements OnDestroy, OnInit {
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private searchService: SearchService, private searchService: SearchService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private routerService: RouterService,
private stateService: StateService, private stateService: StateService,
private eventUploadService: EventUploadService, private eventUploadService: EventUploadService,
private policyService: InternalPolicyService, private policyService: InternalPolicyService,
@ -92,7 +88,7 @@ export class AppComponent implements OnDestroy, OnInit {
private biometricStateService: BiometricStateService, private biometricStateService: BiometricStateService,
private stateEventRunnerService: StateEventRunnerService, private stateEventRunnerService: StateEventRunnerService,
private paymentMethodWarningService: PaymentMethodWarningService, private paymentMethodWarningService: PaymentMethodWarningService,
private organizationService: OrganizationService, private organizationService: InternalOrganizationServiceAbstraction,
) {} ) {}
ngOnInit() { ngOnInit() {

View File

@ -167,7 +167,7 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
qParams.email, qParams.email,
qParams.organizationUserId, qParams.organizationUserId,
); );
policyList = this.policyService.mapPoliciesFromToken(policies); policyList = Policy.fromListResponse(policies);
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);
} }

View File

@ -24,7 +24,6 @@ import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/c
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
@ -60,7 +59,6 @@ export class LoginComponent extends BaseLoginComponent implements OnInit {
logService: LogService, logService: LogService,
ngZone: NgZone, ngZone: NgZone,
protected stateService: StateService, protected stateService: StateService,
private messagingService: MessagingService,
private routerService: RouterService, private routerService: RouterService,
formBuilder: FormBuilder, formBuilder: FormBuilder,
formValidationErrorService: FormValidationErrorsService, formValidationErrorService: FormValidationErrorsService,
@ -122,7 +120,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit {
invite.email, invite.email,
invite.organizationUserId, invite.organizationUserId,
); );
policyList = this.policyService.mapPoliciesFromToken(this.policies); policyList = Policy.fromListResponse(this.policies);
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);
} }

View File

@ -7,7 +7,6 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@ -48,7 +47,6 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
private router: Router, private router: Router,
dialogService: DialogService, dialogService: DialogService,
private userVerificationService: UserVerificationService, private userVerificationService: UserVerificationService,
private configService: ConfigServiceAbstraction,
private keyRotationService: UserKeyRotationService, private keyRotationService: UserKeyRotationService,
) { ) {
super( super(

View File

@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component"; import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -30,6 +31,7 @@ export class EmergencyAccessAttachmentsComponent extends BaseAttachmentsComponen
logService: LogService, logService: LogService,
fileDownloadService: FileDownloadService, fileDownloadService: FileDownloadService,
dialogService: DialogService, dialogService: DialogService,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -42,6 +44,7 @@ export class EmergencyAccessAttachmentsComponent extends BaseAttachmentsComponen
stateService, stateService,
fileDownloadService, fileDownloadService,
dialogService, dialogService,
billingAccountProfileStateService,
); );
} }

View File

@ -28,7 +28,7 @@
bitButton bitButton
buttonType="primary" buttonType="primary"
[bitAction]="invite" [bitAction]="invite"
[disabled]="!canAccessPremium" [disabled]="!(canAccessPremium$ | async)"
> >
<i aria-hidden="true" class="bwi bwi-plus bwi-fw"></i> <i aria-hidden="true" class="bwi bwi-plus bwi-fw"></i>
{{ "addEmergencyContact" | i18n }} {{ "addEmergencyContact" | i18n }}

View File

@ -1,8 +1,9 @@
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { lastValueFrom } from "rxjs"; 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 { 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";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@ -44,7 +45,7 @@ export class EmergencyAccessComponent implements OnInit {
confirmModalRef: ViewContainerRef; confirmModalRef: ViewContainerRef;
loaded = false; loaded = false;
canAccessPremium: boolean; canAccessPremium$: Observable<boolean>;
trustedContacts: GranteeEmergencyAccess[]; trustedContacts: GranteeEmergencyAccess[];
grantedContacts: GrantorEmergencyAccess[]; grantedContacts: GrantorEmergencyAccess[];
emergencyAccessType = EmergencyAccessType; emergencyAccessType = EmergencyAccessType;
@ -62,10 +63,12 @@ export class EmergencyAccessComponent implements OnInit {
private stateService: StateService, private stateService: StateService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
protected dialogService: DialogService, protected dialogService: DialogService,
) {} billingAccountProfileStateService: BillingAccountProfileStateService,
) {
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
}
async ngOnInit() { async ngOnInit() {
this.canAccessPremium = await this.stateService.getCanAccessPremium();
const orgs = await this.organizationService.getAll(); const orgs = await this.organizationService.getAll();
this.isOrganizationOwner = orgs.some((o) => o.isOwner); this.isOrganizationOwner = orgs.some((o) => o.isOwner);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
@ -80,18 +83,21 @@ export class EmergencyAccessComponent implements OnInit {
} }
async premiumRequired() { async premiumRequired() {
if (!this.canAccessPremium) { const canAccessPremium = await firstValueFrom(this.canAccessPremium$);
if (!canAccessPremium) {
this.messagingService.send("premiumRequired"); this.messagingService.send("premiumRequired");
return; return;
} }
} }
edit = async (details: GranteeEmergencyAccess) => { edit = async (details: GranteeEmergencyAccess) => {
const canAccessPremium = await firstValueFrom(this.canAccessPremium$);
const dialogRef = EmergencyAccessAddEditComponent.open(this.dialogService, { const dialogRef = EmergencyAccessAddEditComponent.open(this.dialogService, {
data: { data: {
name: this.userNamePipe.transform(details), name: this.userNamePipe.transform(details),
emergencyAccessId: details?.id, emergencyAccessId: details?.id,
readOnly: !this.canAccessPremium, readOnly: !canAccessPremium,
}, },
}); });

View File

@ -5,6 +5,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
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";
@ -52,6 +53,7 @@ export class EmergencyAddEditCipherComponent extends BaseAddEditComponent {
dialogService: DialogService, dialogService: DialogService,
datePipe: DatePipe, datePipe: DatePipe,
configService: ConfigServiceAbstraction, configService: ConfigServiceAbstraction,
billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
super( super(
cipherService, cipherService,
@ -73,6 +75,7 @@ export class EmergencyAddEditCipherComponent extends BaseAddEditComponent {
dialogService, dialogService,
datePipe, datePipe,
configService, configService,
billingAccountProfileStateService,
); );
} }

View File

@ -70,7 +70,7 @@
type="button" type="button"
bitButton bitButton
buttonType="secondary" buttonType="secondary"
[disabled]="!canAccessPremium && p.premium" [disabled]="!(canAccessPremium$ | async) && p.premium"
(click)="manage(p.type)" (click)="manage(p.type)"
> >
{{ "manage" | i18n }} {{ "manage" | i18n }}

View File

@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core"; import { Component, OnDestroy, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core";
import { Subject, takeUntil } from "rxjs"; import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
@ -9,9 +9,9 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { TwoFactorProviders } from "@bitwarden/common/auth/services/two-factor.service"; import { TwoFactorProviders } from "@bitwarden/common/auth/services/two-factor.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { ProductType } from "@bitwarden/common/enums"; import { ProductType } from "@bitwarden/common/enums";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { TwoFactorAuthenticatorComponent } from "./two-factor-authenticator.component"; import { TwoFactorAuthenticatorComponent } from "./two-factor-authenticator.component";
import { TwoFactorDuoComponent } from "./two-factor-duo.component"; import { TwoFactorDuoComponent } from "./two-factor-duo.component";
@ -40,7 +40,7 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
organizationId: string; organizationId: string;
organization: Organization; organization: Organization;
providers: any[] = []; providers: any[] = [];
canAccessPremium: boolean; canAccessPremium$: Observable<boolean>;
showPolicyWarning = false; showPolicyWarning = false;
loading = true; loading = true;
modal: ModalRef; modal: ModalRef;
@ -56,12 +56,12 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
protected modalService: ModalService, protected modalService: ModalService,
protected messagingService: MessagingService, protected messagingService: MessagingService,
protected policyService: PolicyService, protected policyService: PolicyService,
private stateService: StateService, billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
}
async ngOnInit() { async ngOnInit() {
this.canAccessPremium = await this.stateService.getCanAccessPremium();
for (const key in TwoFactorProviders) { for (const key in TwoFactorProviders) {
// eslint-disable-next-line // eslint-disable-next-line
if (!TwoFactorProviders.hasOwnProperty(key)) { if (!TwoFactorProviders.hasOwnProperty(key)) {
@ -174,7 +174,7 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
} }
async premiumRequired() { async premiumRequired() {
if (!this.canAccessPremium) { if (!(await firstValueFrom(this.canAccessPremium$))) {
this.messagingService.send("premiumRequired"); this.messagingService.send("premiumRequired");
return; return;
} }

View File

@ -7,7 +7,6 @@ import { Subject, takeUntil } from "rxjs";
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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
import { PlanType } from "@bitwarden/common/billing/enums"; import { PlanType } from "@bitwarden/common/billing/enums";
@ -191,8 +190,7 @@ export class TrialInitiationComponent implements OnInit, OnDestroy {
invite.organizationUserId, invite.organizationUserId,
); );
if (policies.data != null) { if (policies.data != null) {
const policiesData = policies.data.map((p) => new PolicyData(p)); this.policies = Policy.fromListResponse(policies);
this.policies = policiesData.map((p) => new Policy(p));
} }
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);

View File

@ -6,7 +6,7 @@
</div> </div>
<bit-callout <bit-callout
type="info" type="info"
*ngIf="canAccessPremium" *ngIf="canAccessPremium$ | async"
title="{{ 'youHavePremiumAccess' | i18n }}" title="{{ 'youHavePremiumAccess' | i18n }}"
icon="bwi bwi-star-f" icon="bwi bwi-star-f"
> >

View File

@ -1,14 +1,15 @@
import { Component, OnInit, ViewChild } from "@angular/core"; import { Component, OnInit, ViewChild } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { firstValueFrom, Observable } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.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";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.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 { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { PaymentComponent, TaxInfoComponent } from "../shared"; import { PaymentComponent, TaxInfoComponent } from "../shared";
@ -20,7 +21,7 @@ export class PremiumComponent implements OnInit {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent; @ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent; @ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent;
canAccessPremium = false; canAccessPremium$: Observable<boolean>;
selfHosted = false; selfHosted = false;
premiumPrice = 10; premiumPrice = 10;
familyPlanMaxUserCount = 6; familyPlanMaxUserCount = 6;
@ -39,17 +40,16 @@ export class PremiumComponent implements OnInit {
private messagingService: MessagingService, private messagingService: MessagingService,
private syncService: SyncService, private syncService: SyncService,
private logService: LogService, private logService: LogService,
private stateService: StateService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
this.selfHosted = platformUtilsService.isSelfHost(); this.selfHosted = platformUtilsService.isSelfHost();
this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl(); this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl();
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
} }
async ngOnInit() { async ngOnInit() {
this.canAccessPremium = await this.stateService.getCanAccessPremium(); if (await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$)) {
const premiumPersonally = await this.stateService.getHasPremiumPersonally();
if (premiumPersonally) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
this.router.navigate(["/settings/subscription/user-subscription"]); this.router.navigate(["/settings/subscription/user-subscription"]);

View File

@ -1,6 +1,8 @@
<app-header> <app-header>
<bit-tab-nav-bar slot="tabs" *ngIf="!selfHosted"> <bit-tab-nav-bar slot="tabs" *ngIf="!selfHosted">
<bit-tab-link [route]="subscriptionRoute">{{ "subscription" | i18n }}</bit-tab-link> <bit-tab-link [route]="(hasPremium$ | async) ? 'user-subscription' : 'premium'">{{
"subscription" | i18n
}}</bit-tab-link>
<bit-tab-link route="payment-method">{{ "paymentMethod" | i18n }}</bit-tab-link> <bit-tab-link route="payment-method">{{ "paymentMethod" | i18n }}</bit-tab-link>
<bit-tab-link route="billing-history">{{ "billingHistory" | i18n }}</bit-tab-link> <bit-tab-link route="billing-history">{{ "billingHistory" | i18n }}</bit-tab-link>
</bit-tab-nav-bar> </bit-tab-nav-bar>

View File

@ -1,26 +1,24 @@
import { Component } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { Observable } from "rxjs";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.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";
@Component({ @Component({
templateUrl: "subscription.component.html", templateUrl: "subscription.component.html",
}) })
export class SubscriptionComponent { export class SubscriptionComponent implements OnInit {
hasPremium: boolean; hasPremium$: Observable<boolean>;
selfHosted: boolean; selfHosted: boolean;
constructor( constructor(
private stateService: StateService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
) {} billingAccountProfileStateService: BillingAccountProfileStateService,
) {
this.hasPremium$ = billingAccountProfileStateService.hasPremiumPersonally$;
}
async ngOnInit() { ngOnInit() {
this.hasPremium = await this.stateService.getHasPremiumPersonally();
this.selfHosted = this.platformUtilsService.isSelfHost(); this.selfHosted = this.platformUtilsService.isSelfHost();
} }
get subscriptionRoute(): string {
return this.hasPremium ? "user-subscription" : "premium";
}
} }

View File

@ -1,8 +1,9 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { lastValueFrom, Observable } from "rxjs"; import { firstValueFrom, lastValueFrom, Observable } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response"; import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
@ -11,7 +12,6 @@ import { FileDownloadService } from "@bitwarden/common/platform/abstractions/fil
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 { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
import { import {
@ -37,7 +37,6 @@ export class UserSubscriptionComponent implements OnInit {
presentUserWithOffboardingSurvey$: Observable<boolean>; presentUserWithOffboardingSurvey$: Observable<boolean>;
constructor( constructor(
private stateService: StateService,
private apiService: ApiService, private apiService: ApiService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService, private i18nService: I18nService,
@ -47,6 +46,7 @@ export class UserSubscriptionComponent implements OnInit {
private dialogService: DialogService, private dialogService: DialogService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private configService: ConfigService, private configService: ConfigService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
this.selfHosted = platformUtilsService.isSelfHost(); this.selfHosted = platformUtilsService.isSelfHost();
this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl(); this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl();
@ -65,8 +65,7 @@ export class UserSubscriptionComponent implements OnInit {
return; return;
} }
// eslint-disable-next-line @typescript-eslint/no-misused-promises if (await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$)) {
if (this.stateService.getHasPremiumPersonally()) {
this.loading = true; this.loading = true;
this.sub = await this.apiService.getUserSubscription(); this.sub = await this.apiService.getUserSubscription();
} else { } else {

View File

@ -150,7 +150,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
async ngOnInit() { async ngOnInit() {
if (this.organizationId) { if (this.organizationId) {
this.organization = this.organizationService.get(this.organizationId); this.organization = await this.organizationService.get(this.organizationId);
this.billing = await this.organizationApiService.getBilling(this.organizationId); this.billing = await this.organizationApiService.getBilling(this.organizationId);
this.sub = await this.organizationApiService.getSubscription(this.organizationId); this.sub = await this.organizationApiService.getSubscription(this.organizationId);
} }

View File

@ -94,7 +94,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
return; return;
} }
this.loading = true; this.loading = true;
this.userOrg = this.organizationService.get(this.organizationId); this.userOrg = await this.organizationService.get(this.organizationId);
if (this.userOrg.canViewSubscription) { if (this.userOrg.canViewSubscription) {
this.sub = await this.organizationApiService.getSubscription(this.organizationId); this.sub = await this.organizationApiService.getSubscription(this.organizationId);
this.lineItems = this.sub?.subscription?.items; this.lineItems = this.sub?.subscription?.items;

View File

@ -110,7 +110,7 @@ export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDest
return; return;
} }
this.loading = true; this.loading = true;
this.userOrg = this.organizationService.get(this.organizationId); this.userOrg = await this.organizationService.get(this.organizationId);
if (this.userOrg.canViewSubscription) { if (this.userOrg.canViewSubscription) {
const subscriptionResponse = await this.organizationApiService.getSubscription( const subscriptionResponse = await this.organizationApiService.getSubscription(
this.organizationId, this.organizationId,

View File

@ -4,32 +4,39 @@ import {
RouterStateSnapshot, RouterStateSnapshot,
Router, Router,
CanActivateFn, CanActivateFn,
UrlTree,
} from "@angular/router"; } from "@angular/router";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
/** /**
* CanActivate guard that checks if the user has premium and otherwise triggers the "premiumRequired" * CanActivate guard that checks if the user has premium and otherwise triggers the "premiumRequired"
* message and blocks navigation. * message and blocks navigation.
*/ */
export function hasPremiumGuard(): CanActivateFn { export function hasPremiumGuard(): CanActivateFn {
return async (_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => { return (
_route: ActivatedRouteSnapshot,
_state: RouterStateSnapshot,
): Observable<boolean | UrlTree> => {
const router = inject(Router); const router = inject(Router);
const stateService = inject(StateService);
const messagingService = inject(MessagingService); const messagingService = inject(MessagingService);
const billingAccountProfileStateService = inject(BillingAccountProfileStateService);
const userHasPremium = await stateService.getCanAccessPremium(); return billingAccountProfileStateService.hasPremiumFromAnySource$.pipe(
tap((userHasPremium: boolean) => {
if (!userHasPremium) { if (!userHasPremium) {
messagingService.send("premiumRequired"); messagingService.send("premiumRequired");
} }
}),
// Prevent trapping the user on the login page, since that's an awful UX flow // Prevent trapping the user on the login page, since that's an awful UX flow
tap((userHasPremium: boolean) => {
if (!userHasPremium && router.url === "/login") { if (!userHasPremium && router.url === "/login") {
return router.createUrlTree(["/"]); return router.createUrlTree(["/"]);
} }
}),
return userHasPremium; );
}; };
} }

View File

@ -7,6 +7,7 @@ import {
STATE_SERVICE_USE_CACHE, STATE_SERVICE_USE_CACHE,
} from "@bitwarden/angular/services/injection-tokens"; } from "@bitwarden/angular/services/injection-tokens";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { import {
@ -33,6 +34,7 @@ export class StateService extends BaseStateService<GlobalState, Account> {
@Inject(STATE_FACTORY) stateFactory: StateFactory<GlobalState, Account>, @Inject(STATE_FACTORY) stateFactory: StateFactory<GlobalState, Account>,
accountService: AccountService, accountService: AccountService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
tokenService: TokenService,
migrationRunner: MigrationRunner, migrationRunner: MigrationRunner,
@Inject(STATE_SERVICE_USE_CACHE) useAccountCache = true, @Inject(STATE_SERVICE_USE_CACHE) useAccountCache = true,
) { ) {
@ -44,6 +46,7 @@ export class StateService extends BaseStateService<GlobalState, Account> {
stateFactory, stateFactory,
accountService, accountService,
environmentService, environmentService,
tokenService,
migrationRunner, migrationRunner,
useAccountCache, useAccountCache,
); );

View File

@ -1,15 +1,16 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core"; import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { RouterModule } from "@angular/router"; import { RouterModule } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
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 { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
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 { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { IconModule, LayoutComponent, NavigationModule } from "@bitwarden/components"; import { IconModule, LayoutComponent, NavigationModule } from "@bitwarden/components";
@ -48,10 +49,10 @@ export class UserLayoutComponent implements OnInit, OnDestroy {
private ngZone: NgZone, private ngZone: NgZone,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
private stateService: StateService,
private apiService: ApiService, private apiService: ApiService,
private syncService: SyncService, private syncService: SyncService,
private configService: ConfigService, private configService: ConfigService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@ -79,16 +80,21 @@ export class UserLayoutComponent implements OnInit, OnDestroy {
} }
async load() { async load() {
const premium = await this.stateService.getHasPremiumPersonally(); const hasPremiumPersonally = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumPersonally$,
);
const hasPremiumFromOrg = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$,
);
const selfHosted = this.platformUtilsService.isSelfHost(); const selfHosted = this.platformUtilsService.isSelfHost();
this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships(); this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships();
const hasPremiumFromOrg = await this.stateService.getHasPremiumFromOrganization();
let billing = null; let billing = null;
if (!selfHosted) { if (!selfHosted) {
// TODO: We should remove the need to call this! // TODO: We should remove the need to call this!
billing = await this.apiService.getUserBillingHistory(); billing = await this.apiService.getUserBillingHistory();
} }
this.hideSubscription = !premium && hasPremiumFromOrg && (selfHosted || billing?.hasNoHistory); this.hideSubscription =
!hasPremiumPersonally && hasPremiumFromOrg && (selfHosted || billing?.hasNoHistory);
} }
} }

View File

@ -2,15 +2,13 @@ import { Component, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms"; import { FormBuilder } from "@angular/forms";
import { concatMap, filter, firstValueFrom, map, Observable, Subject, takeUntil, tap } from "rxjs"; 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 { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; 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 { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { ThemeType } from "@bitwarden/common/platform/enums"; import { ThemeType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
@ -48,13 +46,11 @@ export class PreferencesComponent implements OnInit {
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private policyService: PolicyService, private policyService: PolicyService,
private stateService: StateService,
private i18nService: I18nService, private i18nService: I18nService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private messagingService: MessagingService,
private themeStateService: ThemeStateService, private themeStateService: ThemeStateService,
private settingsService: SettingsService, private domainSettingsService: DomainSettingsService,
private dialogService: DialogService, private dialogService: DialogService,
) { ) {
this.vaultTimeoutOptions = [ this.vaultTimeoutOptions = [
@ -139,7 +135,7 @@ export class PreferencesComponent implements OnInit {
vaultTimeoutAction: await firstValueFrom( vaultTimeoutAction: await firstValueFrom(
this.vaultTimeoutSettingsService.vaultTimeoutAction$(), this.vaultTimeoutSettingsService.vaultTimeoutAction$(),
), ),
enableFavicons: !(await this.settingsService.getDisableFavicon()), enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$),
theme: await firstValueFrom(this.themeStateService.selectedTheme$), theme: await firstValueFrom(this.themeStateService.selectedTheme$),
locale: (await firstValueFrom(this.i18nService.userSetLocale$)) ?? null, locale: (await firstValueFrom(this.i18nService.userSetLocale$)) ?? null,
}; };
@ -162,7 +158,7 @@ export class PreferencesComponent implements OnInit {
values.vaultTimeout, values.vaultTimeout,
values.vaultTimeoutAction, values.vaultTimeoutAction,
); );
await this.settingsService.setDisableFavicon(!values.enableFavicons); await this.domainSettingsService.setShowFavicons(values.enableFavicons);
await this.themeStateService.setSelectedTheme(values.theme); await this.themeStateService.setSelectedTheme(values.theme);
await this.i18nService.setLocale(values.locale); await this.i18nService.setLocale(values.locale);
if (values.locale !== this.startingLocale) { if (values.locale !== this.startingLocale) {

View File

@ -1,13 +1,12 @@
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core"; import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { firstValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "../core";
const BroadcasterSubscriptionId = "SettingsComponent"; const BroadcasterSubscriptionId = "SettingsComponent";
@Component({ @Component({
@ -21,13 +20,12 @@ export class SettingsComponent implements OnInit, OnDestroy {
hideSubscription: boolean; hideSubscription: boolean;
constructor( constructor(
private tokenService: TokenService,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private ngZone: NgZone, private ngZone: NgZone,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
private stateService: StateService,
private apiService: ApiService, private apiService: ApiService,
private billingAccountProfileStateServiceAbstraction: BillingAccountProfileStateService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@ -53,9 +51,13 @@ export class SettingsComponent implements OnInit, OnDestroy {
} }
async load() { async load() {
this.premium = await this.stateService.getHasPremiumPersonally(); this.premium = await firstValueFrom(
this.billingAccountProfileStateServiceAbstraction.hasPremiumPersonally$,
);
this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships(); this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships();
const hasPremiumFromOrg = await this.stateService.getHasPremiumFromOrganization(); const hasPremiumFromOrg = await firstValueFrom(
this.billingAccountProfileStateServiceAbstraction.hasPremiumFromAnyOrganization$,
);
let billing = null; let billing = null;
if (!this.selfHosted) { if (!this.selfHosted) {
billing = await this.apiService.getUserBillingHistory(); billing = await this.apiService.getUserBillingHistory();

View File

@ -8,6 +8,7 @@ import localeBn from "@angular/common/locales/bn";
import localeBs from "@angular/common/locales/bs"; import localeBs from "@angular/common/locales/bs";
import localeCa from "@angular/common/locales/ca"; import localeCa from "@angular/common/locales/ca";
import localeCs from "@angular/common/locales/cs"; import localeCs from "@angular/common/locales/cs";
import localeCy from "@angular/common/locales/cy";
import localeDa from "@angular/common/locales/da"; import localeDa from "@angular/common/locales/da";
import localeDe from "@angular/common/locales/de"; import localeDe from "@angular/common/locales/de";
import localeEl from "@angular/common/locales/el"; import localeEl from "@angular/common/locales/el";
@ -17,9 +18,11 @@ import localeEo from "@angular/common/locales/eo";
import localeEs from "@angular/common/locales/es"; import localeEs from "@angular/common/locales/es";
import localeEt from "@angular/common/locales/et"; import localeEt from "@angular/common/locales/et";
import localeEu from "@angular/common/locales/eu"; import localeEu from "@angular/common/locales/eu";
import localeFa from "@angular/common/locales/fa";
import localeFi from "@angular/common/locales/fi"; import localeFi from "@angular/common/locales/fi";
import localeFil from "@angular/common/locales/fil"; import localeFil from "@angular/common/locales/fil";
import localeFr from "@angular/common/locales/fr"; import localeFr from "@angular/common/locales/fr";
import localeGl from "@angular/common/locales/gl";
import localeHe from "@angular/common/locales/he"; import localeHe from "@angular/common/locales/he";
import localeHi from "@angular/common/locales/hi"; import localeHi from "@angular/common/locales/hi";
import localeHr from "@angular/common/locales/hr"; import localeHr from "@angular/common/locales/hr";
@ -33,9 +36,13 @@ import localeKn from "@angular/common/locales/kn";
import localeKo from "@angular/common/locales/ko"; import localeKo from "@angular/common/locales/ko";
import localeLv from "@angular/common/locales/lv"; import localeLv from "@angular/common/locales/lv";
import localeMl from "@angular/common/locales/ml"; import localeMl from "@angular/common/locales/ml";
import localeMr from "@angular/common/locales/mr";
import localeMy from "@angular/common/locales/my";
import localeNb from "@angular/common/locales/nb"; import localeNb from "@angular/common/locales/nb";
import localeNe from "@angular/common/locales/ne";
import localeNl from "@angular/common/locales/nl"; import localeNl from "@angular/common/locales/nl";
import localeNn from "@angular/common/locales/nn"; import localeNn from "@angular/common/locales/nn";
import localeOr from "@angular/common/locales/or";
import localePl from "@angular/common/locales/pl"; import localePl from "@angular/common/locales/pl";
import localePtBr from "@angular/common/locales/pt"; import localePtBr from "@angular/common/locales/pt";
import localePtPt from "@angular/common/locales/pt-PT"; import localePtPt from "@angular/common/locales/pt-PT";
@ -46,6 +53,8 @@ import localeSk from "@angular/common/locales/sk";
import localeSl from "@angular/common/locales/sl"; import localeSl from "@angular/common/locales/sl";
import localeSr from "@angular/common/locales/sr"; import localeSr from "@angular/common/locales/sr";
import localeSv from "@angular/common/locales/sv"; import localeSv from "@angular/common/locales/sv";
import localeTe from "@angular/common/locales/te";
import localeTh from "@angular/common/locales/th";
import localeTr from "@angular/common/locales/tr"; import localeTr from "@angular/common/locales/tr";
import localeUk from "@angular/common/locales/uk"; import localeUk from "@angular/common/locales/uk";
import localeVi from "@angular/common/locales/vi"; import localeVi from "@angular/common/locales/vi";
@ -61,6 +70,7 @@ registerLocaleData(localeBn, "bn");
registerLocaleData(localeBs, "bs"); registerLocaleData(localeBs, "bs");
registerLocaleData(localeCa, "ca"); registerLocaleData(localeCa, "ca");
registerLocaleData(localeCs, "cs"); registerLocaleData(localeCs, "cs");
registerLocaleData(localeCy, "cy");
registerLocaleData(localeDa, "da"); registerLocaleData(localeDa, "da");
registerLocaleData(localeDe, "de"); registerLocaleData(localeDe, "de");
registerLocaleData(localeEl, "el"); registerLocaleData(localeEl, "el");
@ -70,9 +80,11 @@ registerLocaleData(localeEo, "eo");
registerLocaleData(localeEs, "es"); registerLocaleData(localeEs, "es");
registerLocaleData(localeEt, "et"); registerLocaleData(localeEt, "et");
registerLocaleData(localeEu, "eu"); registerLocaleData(localeEu, "eu");
registerLocaleData(localeFa, "fa");
registerLocaleData(localeFi, "fi"); registerLocaleData(localeFi, "fi");
registerLocaleData(localeFil, "fil"); registerLocaleData(localeFil, "fil");
registerLocaleData(localeFr, "fr"); registerLocaleData(localeFr, "fr");
registerLocaleData(localeGl, "gl");
registerLocaleData(localeHe, "he"); registerLocaleData(localeHe, "he");
registerLocaleData(localeHi, "hi"); registerLocaleData(localeHi, "hi");
registerLocaleData(localeHr, "hr"); registerLocaleData(localeHr, "hr");
@ -86,9 +98,13 @@ registerLocaleData(localeKn, "kn");
registerLocaleData(localeKo, "ko"); registerLocaleData(localeKo, "ko");
registerLocaleData(localeLv, "lv"); registerLocaleData(localeLv, "lv");
registerLocaleData(localeMl, "ml"); registerLocaleData(localeMl, "ml");
registerLocaleData(localeMr, "mr");
registerLocaleData(localeMy, "my");
registerLocaleData(localeNb, "nb"); registerLocaleData(localeNb, "nb");
registerLocaleData(localeNe, "ne");
registerLocaleData(localeNl, "nl"); registerLocaleData(localeNl, "nl");
registerLocaleData(localeNn, "nn"); registerLocaleData(localeNn, "nn");
registerLocaleData(localeOr, "or");
registerLocaleData(localePl, "pl"); registerLocaleData(localePl, "pl");
registerLocaleData(localePtBr, "pt-BR"); registerLocaleData(localePtBr, "pt-BR");
registerLocaleData(localePtPt, "pt-PT"); registerLocaleData(localePtPt, "pt-PT");
@ -99,6 +115,8 @@ registerLocaleData(localeSk, "sk");
registerLocaleData(localeSl, "sl"); registerLocaleData(localeSl, "sl");
registerLocaleData(localeSr, "sr"); registerLocaleData(localeSr, "sr");
registerLocaleData(localeSv, "sv"); registerLocaleData(localeSv, "sv");
registerLocaleData(localeTe, "te");
registerLocaleData(localeTh, "th");
registerLocaleData(localeTr, "tr"); registerLocaleData(localeTr, "tr");
registerLocaleData(localeUk, "uk"); registerLocaleData(localeUk, "uk");
registerLocaleData(localeVi, "vi"); registerLocaleData(localeVi, "vi");

Some files were not shown because too many files have changed in this diff Show More