1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-25858]Organization warnings endpoint should not be called from self-hosted instances (#16781)

* ensure that getWarnings from server is not called for selfhost

* Refactor the code

* move the selfhost check to getWarning message

* Fix the failing test
This commit is contained in:
cyprain-okeke
2025-10-23 16:59:57 +01:00
committed by GitHub
parent d91fdad011
commit 660e452ba1
2 changed files with 68 additions and 2 deletions

View File

@@ -16,6 +16,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogRef, DialogService } from "@bitwarden/components";
import { OrganizationBillingClient } from "@bitwarden/web-vault/app/billing/clients";
import {
@@ -37,6 +38,7 @@ describe("OrganizationWarningsService", () => {
let i18nService: MockProxy<I18nService>;
let organizationApiService: MockProxy<OrganizationApiServiceAbstraction>;
let organizationBillingClient: MockProxy<OrganizationBillingClient>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let router: MockProxy<Router>;
const organization = {
@@ -58,10 +60,13 @@ describe("OrganizationWarningsService", () => {
i18nService = mock<I18nService>();
organizationApiService = mock<OrganizationApiServiceAbstraction>();
organizationBillingClient = mock<OrganizationBillingClient>();
platformUtilsService = mock<PlatformUtilsService>();
router = mock<Router>();
(openChangePlanDialog as jest.Mock).mockReset();
platformUtilsService.isSelfHost.mockReturnValue(false);
i18nService.t.mockImplementation((key: string, ...args: any[]) => {
switch (key) {
case "freeTrialEndPromptCount":
@@ -94,6 +99,7 @@ describe("OrganizationWarningsService", () => {
{ provide: I18nService, useValue: i18nService },
{ provide: OrganizationApiServiceAbstraction, useValue: organizationApiService },
{ provide: OrganizationBillingClient, useValue: organizationBillingClient },
{ provide: PlatformUtilsService, useValue: platformUtilsService },
{ provide: Router, useValue: router },
],
});
@@ -111,6 +117,16 @@ describe("OrganizationWarningsService", () => {
});
});
it("should return null when platform is self-hosted", (done) => {
platformUtilsService.isSelfHost.mockReturnValue(true);
service.getFreeTrialWarning$(organization).subscribe((result) => {
expect(result).toBeNull();
expect(organizationBillingClient.getWarnings).not.toHaveBeenCalled();
done();
});
});
it("should return warning with count message when remaining trial days >= 2", (done) => {
const warning = { remainingTrialDays: 5 };
organizationBillingClient.getWarnings.mockResolvedValue({
@@ -206,6 +222,16 @@ describe("OrganizationWarningsService", () => {
});
});
it("should return null when platform is self-hosted", (done) => {
platformUtilsService.isSelfHost.mockReturnValue(true);
service.getResellerRenewalWarning$(organization).subscribe((result) => {
expect(result).toBeNull();
expect(organizationBillingClient.getWarnings).not.toHaveBeenCalled();
done();
});
});
it("should return upcoming warning with correct type and message", (done) => {
const renewalDate = new Date(2024, 11, 31);
const warning = {
@@ -298,6 +324,16 @@ describe("OrganizationWarningsService", () => {
});
});
it("should return null when platform is self-hosted", (done) => {
platformUtilsService.isSelfHost.mockReturnValue(true);
service.getTaxIdWarning$(organization).subscribe((result) => {
expect(result).toBeNull();
expect(organizationBillingClient.getWarnings).not.toHaveBeenCalled();
done();
});
});
it("should return tax_id_missing type when tax ID is missing", (done) => {
const warning = { type: TaxIdWarningTypes.Missing };
organizationBillingClient.getWarnings.mockResolvedValue({
@@ -427,6 +463,16 @@ describe("OrganizationWarningsService", () => {
});
});
it("should not show dialog when platform is self-hosted", (done) => {
platformUtilsService.isSelfHost.mockReturnValue(true);
service.showInactiveSubscriptionDialog$(organization).subscribe(() => {
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
expect(organizationBillingClient.getWarnings).not.toHaveBeenCalled();
done();
});
});
it("should show contact provider dialog for contact_provider resolution", (done) => {
const warning = { resolution: "contact_provider" };
organizationBillingClient.getWarnings.mockResolvedValue({
@@ -570,6 +616,18 @@ describe("OrganizationWarningsService", () => {
});
});
it("should not show dialog when platform is self-hosted", (done) => {
platformUtilsService.isSelfHost.mockReturnValue(true);
service.showSubscribeBeforeFreeTrialEndsDialog$(organization).subscribe({
complete: () => {
expect(organizationApiService.getSubscription).not.toHaveBeenCalled();
expect(organizationBillingClient.getWarnings).not.toHaveBeenCalled();
done();
},
});
});
it("should open trial payment dialog when free trial warning exists", (done) => {
const warning = { remainingTrialDays: 2 };
const subscription = { id: "sub-123" } as OrganizationSubscriptionResponse;

View File

@@ -8,6 +8,7 @@ import {
map,
merge,
Observable,
of,
Subject,
switchMap,
tap,
@@ -17,6 +18,7 @@ import { take } from "rxjs/operators";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { DialogService } from "@bitwarden/components";
import { OrganizationBillingClient } from "@bitwarden/web-vault/app/billing/clients";
@@ -56,6 +58,7 @@ export class OrganizationWarningsService {
private i18nService: I18nService,
private organizationApiService: OrganizationApiServiceAbstraction,
private organizationBillingClient: OrganizationBillingClient,
private platformUtilsService: PlatformUtilsService,
private router: Router,
) {}
@@ -281,12 +284,17 @@ export class OrganizationWarningsService {
organization: Organization,
extract: (response: OrganizationWarningsResponse) => T | null | undefined,
bypassCache: boolean = false,
): Observable<T | null> =>
this.readThroughWarnings$(organization, bypassCache).pipe(
): Observable<T | null> => {
if (this.platformUtilsService.isSelfHost()) {
return of(null);
}
return this.readThroughWarnings$(organization, bypassCache).pipe(
map((response) => {
const value = extract(response);
return value ? value : null;
}),
take(1),
);
};
}