1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-22 11:45:59 +01:00

[SM-396] Self-enroll Secrets Manager (#4666)

This commit is contained in:
Oscar Hinton 2023-02-21 18:24:55 +01:00 committed by GitHub
parent 581f69256d
commit 3305c808d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import { OrganizationBillingRoutingModule } from "./organization-billing-routing
import { OrganizationBillingTabComponent } from "./organization-billing-tab.component";
import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component";
import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component";
import { SecretsManagerEnrollComponent } from "./secrets-manager/enroll.component";
import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
@NgModule({
@ -25,6 +26,7 @@ import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
OrganizationSubscriptionSelfhostComponent,
OrganizationSubscriptionCloudComponent,
SubscriptionHiddenComponent,
SecretsManagerEnrollComponent,
],
})
export class OrganizationBillingModule {}

View File

@ -108,6 +108,13 @@
*ngIf="showChangePlan"
></app-change-plan>
</ng-container>
<sm-enroll
*ngIf="isAdmin"
[enabled]="sub?.useSecretsManager"
[organizationId]="organizationId"
></sm-enroll>
<h2 class="spaced-header">{{ "manageSubscription" | i18n }}</h2>
<p class="mb-4">{{ subscriptionDesc }}</p>
<ng-container

View File

@ -134,6 +134,10 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
return this.sub.plan.hasAdditionalSeatsOption;
}
get isAdmin() {
return this.userOrg.isAdmin;
}
get isSponsoredSubscription(): boolean {
return this.sub.subscription?.items.some((i) => i.sponsoredSubscriptionItem);
}

View File

@ -0,0 +1,13 @@
<form *ngIf="showSecretsManager" [formGroup]="formGroup" [bitSubmit]="submit">
<h2 class="spaced-header">{{ "secretsManagerBeta" | i18n }}</h2>
<p>{{ "secretsManagerSubscriptionDesc" | i18n }}</p>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="enabled" />
<bit-label>{{ "secretsManagerEnable" | i18n }}</bit-label>
</bit-form-control>
<button bitButton bitFormButton buttonType="primary" type="submit">
{{ "save" | i18n }}
</button>
</form>

View File

@ -0,0 +1,52 @@
import { Component, Input, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationEnrollSecretsManagerRequest } from "@bitwarden/common/models/request/organization/organization-enroll-secrets-manager.request";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { flagEnabled } from "../../../../utils/flags";
@Component({
selector: "sm-enroll",
templateUrl: "enroll.component.html",
})
export class SecretsManagerEnrollComponent implements OnInit {
@Input() enabled: boolean;
@Input() organizationId: string;
protected formGroup = this.formBuilder.group({
enabled: [false],
});
protected showSecretsManager = false;
constructor(
private formBuilder: FormBuilder,
private organizationApiService: OrganizationApiServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private syncService: SyncService
) {
this.showSecretsManager = flagEnabled("secretsManager");
}
ngOnInit(): void {
this.formGroup.setValue({
enabled: this.enabled,
});
}
protected submit = async () => {
this.formGroup.markAllAsTouched();
const request = new OrganizationEnrollSecretsManagerRequest();
request.enabled = this.formGroup.value.enabled;
await this.organizationApiService.updateEnrollSecretsManager(this.organizationId, request);
await this.syncService.fullSync(true);
this.platformUtilsService.showToast("success", null, this.i18nService.t("subscriptionUpdated"));
};
}

View File

@ -6475,5 +6475,11 @@
},
"selectionIsRequired": {
"message": "Selection is required."
},
"secretsManagerSubscriptionDesc": {
"message": "Turn on organization access to the Secrets Manager at no charge during the Beta program. Users can be granted access to the Beta in Members."
},
"secretsManagerEnable": {
"message": "Enable Secrets Manager Beta"
}
}

View File

@ -11,6 +11,7 @@ import { OrganizationSubscriptionUpdateRequest } from "../../models/request/orga
import { OrganizationTaxInfoUpdateRequest } from "../../models/request/organization-tax-info-update.request";
import { OrganizationUpdateRequest } from "../../models/request/organization-update.request";
import { OrganizationUpgradeRequest } from "../../models/request/organization-upgrade.request";
import { OrganizationEnrollSecretsManagerRequest } from "../../models/request/organization/organization-enroll-secrets-manager.request";
import { PaymentRequest } from "../../models/request/payment.request";
import { SeatRequest } from "../../models/request/seat.request";
import { StorageRequest } from "../../models/request/storage.request";
@ -59,4 +60,8 @@ export class OrganizationApiServiceAbstraction {
getSso: (id: string) => Promise<OrganizationSsoResponse>;
updateSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
selfHostedSyncLicense: (id: string) => Promise<void>;
updateEnrollSecretsManager: (
id: string,
request: OrganizationEnrollSecretsManagerRequest
) => Promise<void>;
}

View File

@ -0,0 +1,3 @@
export class OrganizationEnrollSecretsManagerRequest {
enabled: boolean;
}

View File

@ -26,6 +26,7 @@ export class OrganizationResponse extends BaseResponse {
use2fa: boolean;
useApi: boolean;
useResetPassword: boolean;
useSecretsManager: boolean;
hasPublicAndPrivateKeys: boolean;
constructor(response: any) {
@ -53,6 +54,7 @@ export class OrganizationResponse extends BaseResponse {
this.use2fa = this.getResponseProperty("Use2fa");
this.useApi = this.getResponseProperty("UseApi");
this.useResetPassword = this.getResponseProperty("UseResetPassword");
this.useSecretsManager = this.getResponseProperty("UseSecretsManager");
this.hasPublicAndPrivateKeys = this.getResponseProperty("HasPublicAndPrivateKeys");
}
}

View File

@ -13,6 +13,7 @@ import { OrganizationSubscriptionUpdateRequest } from "../../models/request/orga
import { OrganizationTaxInfoUpdateRequest } from "../../models/request/organization-tax-info-update.request";
import { OrganizationUpdateRequest } from "../../models/request/organization-update.request";
import { OrganizationUpgradeRequest } from "../../models/request/organization-upgrade.request";
import { OrganizationEnrollSecretsManagerRequest } from "../../models/request/organization/organization-enroll-secrets-manager.request";
import { PaymentRequest } from "../../models/request/payment.request";
import { SeatRequest } from "../../models/request/seat.request";
import { StorageRequest } from "../../models/request/storage.request";
@ -292,4 +293,14 @@ export class OrganizationApiService implements OrganizationApiServiceAbstraction
false
);
}
async updateEnrollSecretsManager(id: string, request: OrganizationEnrollSecretsManagerRequest) {
await this.apiService.send(
"POST",
"/organizations/" + id + "/enroll-secrets-manager",
request,
true,
true
);
}
}