1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-20 16:07:45 +01:00

[PM-13345]Add the new policy (#11894)

* Add the new policy

* Add the free family policy behind flag

* Patch build process

* Revert "Patch build process"

This reverts commit 4024e974b1.

* [PM-13346] Email notification impacts (#11967)

* Changes error notification for disabled offer

* Add the feature to the change

* Add the missing dot

* Remove the authenicated endpoint

* Add the changes for error toast

* Resolve the lint issue

* rename file a correctly

* Remove the floating promise comments

* Delete unwanted comments

---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
cyprain-okeke 2024-11-19 17:36:52 +01:00 committed by GitHub
parent 0386b7f068
commit c17f582768
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 110 additions and 13 deletions

View File

@ -1,7 +1,12 @@
import { Component } from "@angular/core";
import { Component, inject } from "@angular/core";
import { Params } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
import { OrganizationSponsorshipResponse } from "@bitwarden/common/admin-console/models/response/organization-sponsorship.response";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { ToastService } from "@bitwarden/components";
import { BaseAcceptComponent } from "../../../common/base.accept.component";
/*
@ -19,17 +24,18 @@ export class AcceptFamilySponsorshipComponent extends BaseAcceptComponent {
requiredParameters = ["email", "token"];
policyResponse!: OrganizationSponsorshipResponse;
policyApiService = inject(PolicyApiServiceAbstraction);
configService = inject(ConfigService);
toastService = inject(ToastService);
async authedHandler(qParams: Params) {
// 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
this.router.navigate(["/setup/families-for-enterprise"], { queryParams: qParams });
await this.router.navigate(["/setup/families-for-enterprise"], { queryParams: qParams });
}
async unauthedHandler(qParams: Params) {
if (!qParams.register) {
// 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
this.router.navigate(["/login"], { queryParams: { email: qParams.email } });
await this.router.navigate(["/login"], { queryParams: { email: qParams.email } });
} else {
// TODO: update logic when email verification flag is removed
let queryParams: Params;

View File

@ -9,6 +9,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationSponsorshipRedeemRequest } from "@bitwarden/common/admin-console/models/request/organization/organization-sponsorship-redeem.request";
import { PreValidateSponsorshipResponse } from "@bitwarden/common/admin-console/models/response/pre-validate-sponsorship.response";
import { PlanSponsorshipType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -51,6 +52,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy {
showNewOrganization = false;
_organizationPlansComponent: OrganizationPlansComponent;
preValidateSponsorshipResponse: PreValidateSponsorshipResponse;
_selectedFamilyOrganizationId = "";
private _destroy = new Subject<void>();
@ -92,7 +94,20 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy {
this.token = qParams.token;
await this.syncService.fullSync(true);
this.badToken = !(await this.apiService.postPreValidateSponsorshipToken(this.token));
this.preValidateSponsorshipResponse = await this.apiService.postPreValidateSponsorshipToken(
this.token,
);
if (this.preValidateSponsorshipResponse.isFreeFamilyPolicyEnabled) {
this.toastService.showToast({
variant: "error",
title: this.i18nService.t("errorOccured"),
message: this.i18nService.t("offerNoLongerValid"),
});
} else {
this.badToken = !this.preValidateSponsorshipResponse.isTokenValid;
}
this.loading = false;
});

View File

@ -6376,6 +6376,9 @@
"idpSingleSignOnServiceUrlRequired": {
"message": "Required if Entity ID is not a URL."
},
"offerNoLongerValid": {
"message": "This offer is no longer valid. Contact your organization administrators for more information."
},
"openIdOptionalCustomizations": {
"message": "Optional customizations"
},
@ -9727,5 +9730,11 @@
},
"deletedSuccessfully": {
"message": "Deleted successfully"
},
"freeFamiliesSponsorship": {
"message": "Remove Free Bitwarden Families sponsorship"
},
"freeFamiliesSponsorshipPolicyDesc": {
"message": "Do not allow members to redeem a Families plan through this organization."
}
}

View File

@ -7,6 +7,7 @@ import { ActivateAutofillPolicy } from "./admin-console/policies/activate-autofi
import { AutomaticAppLoginPolicy } from "./admin-console/policies/automatic-app-login.component";
import { DisablePersonalVaultExportPolicy } from "./admin-console/policies/disable-personal-vault-export.component";
import { MaximumVaultTimeoutPolicy } from "./admin-console/policies/maximum-vault-timeout.component";
import { FreeFamiliesSponsorshipPolicy } from "./billing/policies/free-families-sponsorship.component";
@Component({
selector: "app-root",
@ -19,9 +20,17 @@ export class AppComponent extends BaseAppComponent implements OnInit {
this.policyListService.addPolicies([
new MaximumVaultTimeoutPolicy(),
new DisablePersonalVaultExportPolicy(),
new ActivateAutofillPolicy(),
]);
this.configService
.getFeatureFlag(FeatureFlag.DisableFreeFamiliesSponsorship)
.then((isFreeFamilyEnabled) => {
if (isFreeFamilyEnabled) {
this.policyListService.addPolicies([new FreeFamiliesSponsorshipPolicy()]);
}
this.policyListService.addPolicies([new ActivateAutofillPolicy()]);
});
this.configService.getFeatureFlag(FeatureFlag.IdpAutoSubmitLogin).then((enabled) => {
if (
enabled &&

View File

@ -19,6 +19,7 @@ import { DisablePersonalVaultExportPolicyComponent } from "./admin-console/polic
import { MaximumVaultTimeoutPolicyComponent } from "./admin-console/policies/maximum-vault-timeout.component";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { FreeFamiliesSponsorshipPolicyComponent } from "./billing/policies/free-families-sponsorship.component";
/**
* This is the AppModule for the commercial version of Bitwarden.
@ -49,6 +50,7 @@ import { AppComponent } from "./app.component";
MaximumVaultTimeoutPolicyComponent,
ActivateAutofillPolicyComponent,
AutomaticAppLoginPolicyComponent,
FreeFamiliesSponsorshipPolicyComponent,
],
bootstrap: [AppComponent],
})

View File

@ -0,0 +1,4 @@
<bit-form-control>
<input type="checkbox" id="enabled" bitCheckbox [formControl]="enabled" />
<bit-label>{{ "turnOn" | i18n }}</bit-label>
</bit-form-control>

View File

@ -0,0 +1,20 @@
import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import {
BasePolicy,
BasePolicyComponent,
} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
export class FreeFamiliesSponsorshipPolicy extends BasePolicy {
name = "freeFamiliesSponsorship";
description = "freeFamiliesSponsorshipPolicyDesc";
type = PolicyType.FreeFamiliesSponsorshipPolicy;
component = FreeFamiliesSponsorshipPolicyComponent;
}
@Component({
selector: "policy-personal-ownership",
templateUrl: "free-families-sponsorship.component.html",
})
export class FreeFamiliesSponsorshipPolicyComponent extends BasePolicyComponent {}

View File

@ -24,6 +24,7 @@ import {
} from "../admin-console/models/response/organization-connection.response";
import { OrganizationExportResponse } from "../admin-console/models/response/organization-export.response";
import { OrganizationSponsorshipSyncStatusResponse } from "../admin-console/models/response/organization-sponsorship-sync-status.response";
import { PreValidateSponsorshipResponse } from "../admin-console/models/response/pre-validate-sponsorship.response";
import {
ProviderOrganizationOrganizationDetailsResponse,
ProviderOrganizationResponse,
@ -490,7 +491,9 @@ export abstract class ApiService {
) => Promise<OrganizationSponsorshipSyncStatusResponse>;
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
postPreValidateSponsorshipToken: (
sponsorshipToken: string,
) => Promise<PreValidateSponsorshipResponse>;
postRedeemSponsorship: (
sponsorshipToken: string,
request: OrganizationSponsorshipRedeemRequest,

View File

@ -12,4 +12,5 @@ export enum PolicyType {
DisablePersonalVaultExport = 10, // Disable personal vault export
ActivateAutofill = 11, // Activates autofill with page load on the browser extension
AutomaticAppLogIn = 12, // Enables automatic log in of apps from configured identity provider
FreeFamiliesSponsorshipPolicy = 13, // Disables free families plan for organization
}

View File

@ -0,0 +1,10 @@
import { BaseResponse } from "../../../models/response/base.response";
export class OrganizationSponsorshipResponse extends BaseResponse {
isPolicyEnabled: string;
constructor(response: any) {
super(response);
this.isPolicyEnabled = this.getResponseProperty("IsPolicyEnabled");
}
}

View File

@ -0,0 +1,12 @@
import { BaseResponse } from "../../../models/response/base.response";
export class PreValidateSponsorshipResponse extends BaseResponse {
isTokenValid: boolean;
isFreeFamilyPolicyEnabled: boolean;
constructor(response: any) {
super(response);
this.isTokenValid = this.getResponseProperty("IsTokenValid");
this.isFreeFamilyPolicyEnabled = this.getResponseProperty("IsFreeFamilyPolicyEnabled");
}
}

View File

@ -39,6 +39,7 @@ export enum FeatureFlag {
SecurityTasks = "security-tasks",
NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss",
NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss",
DisableFreeFamiliesSponsorship = "PM-12274-disable-free-families-sponsorship",
}
export type AllowedFeatureFlagTypes = boolean | number | string;
@ -88,6 +89,7 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.SecurityTasks]: FALSE,
[FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE,
[FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE,
[FeatureFlag.DisableFreeFamiliesSponsorship]: FALSE,
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;

View File

@ -29,6 +29,7 @@ import {
} from "../admin-console/models/response/organization-connection.response";
import { OrganizationExportResponse } from "../admin-console/models/response/organization-export.response";
import { OrganizationSponsorshipSyncStatusResponse } from "../admin-console/models/response/organization-sponsorship-sync-status.response";
import { PreValidateSponsorshipResponse } from "../admin-console/models/response/pre-validate-sponsorship.response";
import {
ProviderOrganizationOrganizationDetailsResponse,
ProviderOrganizationResponse,
@ -1680,8 +1681,10 @@ export class ApiService implements ApiServiceAbstraction {
);
}
async postPreValidateSponsorshipToken(sponsorshipToken: string): Promise<boolean> {
const r = await this.send(
async postPreValidateSponsorshipToken(
sponsorshipToken: string,
): Promise<PreValidateSponsorshipResponse> {
const response = await this.send(
"POST",
"/organization/sponsorship/validate-token?sponsorshipToken=" +
encodeURIComponent(sponsorshipToken),
@ -1689,7 +1692,8 @@ export class ApiService implements ApiServiceAbstraction {
true,
true,
);
return r as boolean;
return new PreValidateSponsorshipResponse(response);
}
async postRedeemSponsorship(