mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 05:13:29 +00:00
[PM-14613] Remove account deprovisioning feature flag (#14353)
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
||||
} from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { Router } from "@angular/router";
|
||||
import { filter, firstValueFrom, map, Subject, takeUntil, timeout, withLatestFrom } from "rxjs";
|
||||
import { filter, firstValueFrom, map, Subject, switchMap, takeUntil, timeout } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { DeviceTrustToastService } from "@bitwarden/angular/auth/services/device-trust-toast.service.abstraction";
|
||||
@@ -29,7 +29,6 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
|
||||
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
@@ -820,27 +819,26 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async deleteAccount() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning).pipe(
|
||||
withLatestFrom(this.organizationService.organizations$(userId)),
|
||||
map(async ([accountDeprovisioningEnabled, organization]) => {
|
||||
if (
|
||||
accountDeprovisioningEnabled &&
|
||||
organization.some((o) => o.userIsManagedByOrganization === true)
|
||||
) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "cannotDeleteAccount" },
|
||||
content: { key: "cannotDeleteAccountDesc" },
|
||||
cancelButtonText: null,
|
||||
acceptButtonText: { key: "close" },
|
||||
type: "danger",
|
||||
});
|
||||
} else {
|
||||
DeleteAccountComponent.open(this.dialogService);
|
||||
}
|
||||
}),
|
||||
const userIsManaged = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.organizationService.organizations$(userId)),
|
||||
map((orgs) => orgs.some((o) => o.userIsManagedByOrganization === true)),
|
||||
),
|
||||
);
|
||||
|
||||
if (userIsManaged) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "cannotDeleteAccount" },
|
||||
content: { key: "cannotDeleteAccountDesc" },
|
||||
cancelButtonText: null,
|
||||
acceptButtonText: { key: "close" },
|
||||
type: "danger",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteAccountComponent.open(this.dialogService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +50,15 @@ export abstract class BaseMembersComponent<UserView extends UserViewTypes> {
|
||||
}
|
||||
|
||||
get showBulkConfirmUsers(): boolean {
|
||||
return this.dataSource.acceptedUserCount > 0;
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Accepted);
|
||||
}
|
||||
|
||||
get showBulkReinviteUsers(): boolean {
|
||||
return this.dataSource.invitedUserCount > 0;
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Invited);
|
||||
}
|
||||
|
||||
abstract userType: typeof OrganizationUserType | typeof ProviderUserType;
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
*ngIf="canAccessExport$ | async"
|
||||
></bit-nav-item>
|
||||
<bit-nav-item
|
||||
[text]="domainVerificationNavigationTextKey | i18n"
|
||||
[text]="'claimedDomains' | i18n"
|
||||
route="settings/domain-verification"
|
||||
*ngIf="organization?.canManageDomainVerification"
|
||||
></bit-nav-item>
|
||||
|
||||
@@ -55,7 +55,6 @@ export class OrganizationLayoutComponent implements OnInit {
|
||||
protected readonly logo = AdminConsoleLogo;
|
||||
|
||||
protected orgFilter = (org: Organization) => canAccessOrgAdmin(org);
|
||||
protected domainVerificationNavigationTextKey: string;
|
||||
|
||||
protected integrationPageEnabled$: Observable<boolean>;
|
||||
|
||||
@@ -146,12 +145,6 @@ export class OrganizationLayoutComponent implements OnInit {
|
||||
|
||||
this.integrationPageEnabled$ = this.organization$.pipe(map((org) => org.canAccessIntegrations));
|
||||
|
||||
this.domainVerificationNavigationTextKey = (await this.configService.getFeatureFlag(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
))
|
||||
? "claimedDomains"
|
||||
: "domainVerification";
|
||||
|
||||
this.canShowPoliciesTab$ = this.organization$.pipe(
|
||||
switchMap((organization) =>
|
||||
this.organizationBillingService
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { DIALOG_DATA, DialogConfig, DialogService } from "@bitwarden/components";
|
||||
|
||||
@@ -35,7 +32,6 @@ export class BulkDeleteDialogComponent {
|
||||
@Inject(DIALOG_DATA) protected dialogParams: BulkDeleteDialogParams,
|
||||
protected i18nService: I18nService,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private configService: ConfigService,
|
||||
private deleteManagedMemberWarningService: DeleteManagedMemberWarningService,
|
||||
) {
|
||||
this.organizationId = dialogParams.organizationId;
|
||||
@@ -43,11 +39,7 @@ export class BulkDeleteDialogComponent {
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (
|
||||
await firstValueFrom(this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning))
|
||||
) {
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.organizationId);
|
||||
}
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.organizationId);
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<bit-dialog
|
||||
dialogSize="large"
|
||||
*ngIf="{ enabled: accountDeprovisioningEnabled$ | async } as accountDeprovisioning"
|
||||
>
|
||||
<bit-dialog dialogSize="large">
|
||||
<ng-container bitDialogTitle>
|
||||
<span *ngIf="accountDeprovisioning.enabled; else nonMemberTitle">{{ bulkMemberTitle }}</span>
|
||||
<ng-template #nonMemberTitle>
|
||||
{{ bulkTitle }}
|
||||
</ng-template>
|
||||
<span>{{ bulkTitle }}</span>
|
||||
</ng-container>
|
||||
|
||||
<div bitDialogContent>
|
||||
@@ -20,7 +14,7 @@
|
||||
|
||||
<bit-callout
|
||||
type="danger"
|
||||
*ngIf="nonCompliantMembers && accountDeprovisioning.enabled"
|
||||
*ngIf="nonCompliantMembers"
|
||||
title="{{ 'nonCompliantMembersTitle' | i18n }}"
|
||||
>
|
||||
{{ "nonCompliantMembersError" | i18n }}
|
||||
@@ -50,7 +44,7 @@
|
||||
<bit-table>
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell>{{ (accountDeprovisioning.enabled ? "member" : "user") | i18n }}</th>
|
||||
<th bitCell>{{ "member" | i18n }}</th>
|
||||
<th bitCell class="tw-w-1/2" *ngIf="this.showNoMasterPasswordWarning">
|
||||
{{ "details" | i18n }}
|
||||
</th>
|
||||
@@ -82,7 +76,7 @@
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell class="tw-w-1/2">
|
||||
{{ (accountDeprovisioning.enabled ? "member" : "user") | i18n }}
|
||||
{{ "member" | i18n }}
|
||||
</th>
|
||||
<th bitCell class="tw-w-1/2">{{ "status" | i18n }}</th>
|
||||
</tr>
|
||||
@@ -113,7 +107,7 @@
|
||||
[bitAction]="submit"
|
||||
buttonType="primary"
|
||||
>
|
||||
{{ accountDeprovisioning.enabled ? bulkMemberTitle : bulkTitle }}
|
||||
{{ bulkTitle }}
|
||||
</button>
|
||||
<button type="button" bitButton buttonType="secondary" bitDialogClose>
|
||||
{{ "close" | i18n }}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { DIALOG_DATA, DialogService } from "@bitwarden/components";
|
||||
|
||||
@@ -34,12 +31,10 @@ export class BulkRestoreRevokeComponent {
|
||||
error: string;
|
||||
showNoMasterPasswordWarning = false;
|
||||
nonCompliantMembers: boolean = false;
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
protected i18nService: I18nService,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private configService: ConfigService,
|
||||
@Inject(DIALOG_DATA) protected data: BulkRestoreDialogParams,
|
||||
) {
|
||||
this.isRevoking = data.isRevoking;
|
||||
@@ -48,17 +43,9 @@ export class BulkRestoreRevokeComponent {
|
||||
this.showNoMasterPasswordWarning = this.users.some(
|
||||
(u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false,
|
||||
);
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
|
||||
get bulkTitle() {
|
||||
const titleKey = this.isRevoking ? "revokeUsers" : "restoreUsers";
|
||||
return this.i18nService.t(titleKey);
|
||||
}
|
||||
|
||||
get bulkMemberTitle() {
|
||||
const titleKey = this.isRevoking ? "revokeMembers" : "restoreMembers";
|
||||
return this.i18nService.t(titleKey);
|
||||
}
|
||||
|
||||
@@ -275,11 +275,7 @@
|
||||
{{ "revoke" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="
|
||||
this.editMode &&
|
||||
(!(accountDeprovisioningEnabled$ | async) ||
|
||||
!(editParams$ | async)?.managedByOrganization)
|
||||
"
|
||||
*ngIf="this.editMode && !(editParams$ | async)?.managedByOrganization"
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
bitButton
|
||||
@@ -290,11 +286,7 @@
|
||||
{{ "remove" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="
|
||||
this.editMode &&
|
||||
(accountDeprovisioningEnabled$ | async) &&
|
||||
(editParams$ | async)?.managedByOrganization
|
||||
"
|
||||
*ngIf="this.editMode && (editParams$ | async)?.managedByOrganization"
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
bitButton
|
||||
|
||||
@@ -152,10 +152,6 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
manageResetPassword: false,
|
||||
});
|
||||
|
||||
protected accountDeprovisioningEnabled$: Observable<boolean> = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
protected isExternalIdVisible$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.SsoExternalIdVisibility)
|
||||
.pipe(
|
||||
@@ -667,11 +663,9 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
const showWarningDialog = combineLatest([
|
||||
this.organization$,
|
||||
this.deleteManagedMemberWarningService.warningAcknowledged(this.params.organizationId),
|
||||
this.accountDeprovisioningEnabled$,
|
||||
]).pipe(
|
||||
map(
|
||||
([organization, acknowledged, featureFlagEnabled]) =>
|
||||
featureFlagEnabled &&
|
||||
([organization, acknowledged]) =>
|
||||
organization.canManageUsers &&
|
||||
organization.productTierType === ProductTierType.Enterprise &&
|
||||
!acknowledged,
|
||||
@@ -714,9 +708,8 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
message: this.i18nService.t("organizationUserDeleted", this.params.name),
|
||||
});
|
||||
|
||||
if (await firstValueFrom(this.accountDeprovisioningEnabled$)) {
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.params.organizationId);
|
||||
}
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.params.organizationId);
|
||||
|
||||
this.close(MemberDialogResult.Deleted);
|
||||
};
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
{{ "revokeAccess" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="!accountDeprovisioningEnabled || !u.managedByOrganization"
|
||||
*ngIf="!u.managedByOrganization"
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="remove(u)"
|
||||
@@ -355,7 +355,7 @@
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="accountDeprovisioningEnabled && u.managedByOrganization"
|
||||
*ngIf="u.managedByOrganization"
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="deleteUser(u)"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { Component, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import {
|
||||
@@ -46,9 +46,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||
import { isNotSelfUpgradable, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
@@ -91,7 +89,7 @@ class MembersTableDataSource extends PeopleTableDataSource<OrganizationUserView>
|
||||
@Component({
|
||||
templateUrl: "members.component.html",
|
||||
})
|
||||
export class MembersComponent extends BaseMembersComponent<OrganizationUserView> implements OnInit {
|
||||
export class MembersComponent extends BaseMembersComponent<OrganizationUserView> {
|
||||
@ViewChild("resetPasswordTemplate", { read: ViewContainerRef, static: true })
|
||||
resetPasswordModalRef: ViewContainerRef;
|
||||
|
||||
@@ -104,7 +102,6 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
status: OrganizationUserStatusType = null;
|
||||
orgResetPasswordPolicyEnabled = false;
|
||||
orgIsOnSecretsManagerStandalone = false;
|
||||
accountDeprovisioningEnabled = false;
|
||||
|
||||
protected canUseSecretsManager$: Observable<boolean>;
|
||||
|
||||
@@ -139,7 +136,6 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
private groupService: GroupApiService,
|
||||
private collectionService: CollectionService,
|
||||
private billingApiService: BillingApiServiceAbstraction,
|
||||
private configService: ConfigService,
|
||||
protected deleteManagedMemberWarningService: DeleteManagedMemberWarningService,
|
||||
) {
|
||||
super(
|
||||
@@ -237,12 +233,6 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.accountDeprovisioningEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
|
||||
async getUsers(): Promise<OrganizationUserView[]> {
|
||||
let groupsPromise: Promise<Map<string, string>>;
|
||||
let collectionsPromise: Promise<Map<string, string>>;
|
||||
@@ -591,20 +581,18 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
}
|
||||
|
||||
async bulkDelete() {
|
||||
if (this.accountDeprovisioningEnabled) {
|
||||
const warningAcknowledged = await firstValueFrom(
|
||||
this.deleteManagedMemberWarningService.warningAcknowledged(this.organization.id),
|
||||
);
|
||||
const warningAcknowledged = await firstValueFrom(
|
||||
this.deleteManagedMemberWarningService.warningAcknowledged(this.organization.id),
|
||||
);
|
||||
|
||||
if (
|
||||
!warningAcknowledged &&
|
||||
this.organization.canManageUsers &&
|
||||
this.organization.productTierType === ProductTierType.Enterprise
|
||||
) {
|
||||
const acknowledged = await this.deleteManagedMemberWarningService.showWarning();
|
||||
if (!acknowledged) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!warningAcknowledged &&
|
||||
this.organization.canManageUsers &&
|
||||
this.organization.productTierType === ProductTierType.Enterprise
|
||||
) {
|
||||
const acknowledged = await this.deleteManagedMemberWarningService.showWarning();
|
||||
if (!acknowledged) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,20 +782,18 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
}
|
||||
|
||||
async deleteUser(user: OrganizationUserView) {
|
||||
if (this.accountDeprovisioningEnabled) {
|
||||
const warningAcknowledged = await firstValueFrom(
|
||||
this.deleteManagedMemberWarningService.warningAcknowledged(this.organization.id),
|
||||
);
|
||||
const warningAcknowledged = await firstValueFrom(
|
||||
this.deleteManagedMemberWarningService.warningAcknowledged(this.organization.id),
|
||||
);
|
||||
|
||||
if (
|
||||
!warningAcknowledged &&
|
||||
this.organization.canManageUsers &&
|
||||
this.organization.productTierType === ProductTierType.Enterprise
|
||||
) {
|
||||
const acknowledged = await this.deleteManagedMemberWarningService.showWarning();
|
||||
if (!acknowledged) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!warningAcknowledged &&
|
||||
this.organization.canManageUsers &&
|
||||
this.organization.productTierType === ProductTierType.Enterprise
|
||||
) {
|
||||
const acknowledged = await this.deleteManagedMemberWarningService.showWarning();
|
||||
if (!acknowledged) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,9 +815,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.accountDeprovisioningEnabled) {
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.organization.id);
|
||||
}
|
||||
await this.deleteManagedMemberWarningService.acknowledgeWarning(this.organization.id);
|
||||
|
||||
this.actionPromise = this.organizationUserApiService.deleteOrganizationUser(
|
||||
this.organization.id,
|
||||
@@ -864,56 +848,23 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
});
|
||||
}
|
||||
|
||||
get showBulkConfirmUsers(): boolean {
|
||||
if (!this.accountDeprovisioningEnabled) {
|
||||
return super.showBulkConfirmUsers;
|
||||
}
|
||||
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Accepted);
|
||||
}
|
||||
|
||||
get showBulkReinviteUsers(): boolean {
|
||||
if (!this.accountDeprovisioningEnabled) {
|
||||
return super.showBulkReinviteUsers;
|
||||
}
|
||||
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Invited);
|
||||
}
|
||||
|
||||
get showBulkRestoreUsers(): boolean {
|
||||
return (
|
||||
!this.accountDeprovisioningEnabled ||
|
||||
this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Revoked)
|
||||
);
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status == this.userStatusType.Revoked);
|
||||
}
|
||||
|
||||
get showBulkRevokeUsers(): boolean {
|
||||
return (
|
||||
!this.accountDeprovisioningEnabled ||
|
||||
this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status != this.userStatusType.Revoked)
|
||||
);
|
||||
return this.dataSource
|
||||
.getCheckedUsers()
|
||||
.every((member) => member.status != this.userStatusType.Revoked);
|
||||
}
|
||||
|
||||
get showBulkRemoveUsers(): boolean {
|
||||
return (
|
||||
!this.accountDeprovisioningEnabled ||
|
||||
this.dataSource.getCheckedUsers().every((member) => !member.managedByOrganization)
|
||||
);
|
||||
return this.dataSource.getCheckedUsers().every((member) => !member.managedByOrganization);
|
||||
}
|
||||
|
||||
get showBulkDeleteUsers(): boolean {
|
||||
if (!this.accountDeprovisioningEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const validStatuses = [
|
||||
this.userStatusType.Accepted,
|
||||
this.userStatusType.Confirmed,
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<bit-callout *ngIf="accountDeprovisioningEnabled$ | async; else disabledBlock" type="warning">
|
||||
<bit-callout type="warning">
|
||||
{{ "singleOrgPolicyMemberWarning" | i18n }}
|
||||
</bit-callout>
|
||||
<ng-template #disabledBlock>
|
||||
<bit-callout type="warning">
|
||||
{{ "singleOrgPolicyWarning" | i18n }}
|
||||
</bit-callout>
|
||||
</ng-template>
|
||||
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox [formControl]="enabled" id="enabled" />
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
|
||||
import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
|
||||
|
||||
export class SingleOrgPolicy extends BasePolicy {
|
||||
name = "singleOrg";
|
||||
description = "singleOrgDesc";
|
||||
description = "singleOrgPolicyDesc";
|
||||
type = PolicyType.SingleOrg;
|
||||
component = SingleOrgPolicyComponent;
|
||||
}
|
||||
@@ -19,22 +16,9 @@ export class SingleOrgPolicy extends BasePolicy {
|
||||
templateUrl: "single-org.component.html",
|
||||
})
|
||||
export class SingleOrgPolicyComponent extends BasePolicyComponent implements OnInit {
|
||||
constructor(private configService: ConfigService) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected accountDeprovisioningEnabled$: Observable<boolean> = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
async ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
const isAccountDeprovisioningEnabled = await firstValueFrom(this.accountDeprovisioningEnabled$);
|
||||
this.policy.description = isAccountDeprovisioningEnabled
|
||||
? "singleOrgPolicyDesc"
|
||||
: "singleOrgDesc";
|
||||
|
||||
if (!this.policyResponse.canToggleState) {
|
||||
this.enabled.disable();
|
||||
}
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
import { Component, OnInit, OnDestroy } from "@angular/core";
|
||||
import {
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
from,
|
||||
lastValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
Subject,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
import { firstValueFrom, from, lastValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@@ -47,10 +37,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
const isAccountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
const userIsManagedByOrganization$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
@@ -61,25 +47,14 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.showChangeEmail$ = hasMasterPassword$;
|
||||
|
||||
this.showPurgeVault$ = combineLatest([
|
||||
isAccountDeprovisioningEnabled$,
|
||||
userIsManagedByOrganization$,
|
||||
]).pipe(
|
||||
map(
|
||||
([isAccountDeprovisioningEnabled, userIsManagedByOrganization]) =>
|
||||
!isAccountDeprovisioningEnabled || !userIsManagedByOrganization,
|
||||
),
|
||||
this.showPurgeVault$ = userIsManagedByOrganization$.pipe(
|
||||
map((userIsManagedByOrganization) => !userIsManagedByOrganization),
|
||||
);
|
||||
|
||||
this.showDeleteAccount$ = combineLatest([
|
||||
isAccountDeprovisioningEnabled$,
|
||||
userIsManagedByOrganization$,
|
||||
]).pipe(
|
||||
map(
|
||||
([isAccountDeprovisioningEnabled, userIsManagedByOrganization]) =>
|
||||
!isAccountDeprovisioningEnabled || !userIsManagedByOrganization,
|
||||
),
|
||||
this.showDeleteAccount$ = userIsManagedByOrganization$.pipe(
|
||||
map((userIsManagedByOrganization) => !userIsManagedByOrganization),
|
||||
);
|
||||
|
||||
this.accountService.accountVerifyNewDeviceLogin$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((verifyDevices) => {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { TypographyModule } from "@bitwarden/components";
|
||||
|
||||
/**
|
||||
@@ -18,13 +15,4 @@ import { TypographyModule } from "@bitwarden/components";
|
||||
standalone: true,
|
||||
imports: [TypographyModule, JslibModule, CommonModule],
|
||||
})
|
||||
export class DangerZoneComponent implements OnInit {
|
||||
constructor(private configService: ConfigService) {}
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
}
|
||||
export class DangerZoneComponent {}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormControl, FormGroup } from "@angular/forms";
|
||||
import { firstValueFrom, map, Observable, of, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -10,9 +10,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/update-profile.request";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ProfileResponse } from "@bitwarden/common/models/response/profile.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
@@ -40,7 +38,6 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
private accountService: AccountService,
|
||||
private dialogService: DialogService,
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
private organizationService: OrganizationService,
|
||||
) {}
|
||||
|
||||
@@ -53,21 +50,12 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
this.managingOrganization$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.AccountDeprovisioning)
|
||||
this.managingOrganization$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
switchMap((isAccountDeprovisioningEnabled) =>
|
||||
isAccountDeprovisioningEnabled
|
||||
? this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
: of(null),
|
||||
),
|
||||
map((organizations) => organizations.find((o) => o.userIsManagedByOrganization === true)),
|
||||
);
|
||||
|
||||
this.formGroup.get("name").setValue(this.profile.name);
|
||||
this.formGroup.get("email").setValue(this.profile.email);
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { DeviceType, EventType } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { EventResponse } from "@bitwarden/common/models/response/event.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
@Injectable()
|
||||
@@ -21,8 +19,7 @@ export class EventService {
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
policyService: PolicyService,
|
||||
private configService: ConfigService,
|
||||
private accountService: AccountService,
|
||||
accountService: AccountService,
|
||||
) {
|
||||
accountService.activeAccount$
|
||||
.pipe(
|
||||
@@ -463,20 +460,10 @@ export class EventService {
|
||||
msg = humanReadableMsg = this.i18nService.t("removedDomain", ev.domainName);
|
||||
break;
|
||||
case EventType.OrganizationDomain_Verified:
|
||||
msg = humanReadableMsg = this.i18nService.t(
|
||||
(await this.configService.getFeatureFlag(FeatureFlag.AccountDeprovisioning))
|
||||
? "domainClaimedEvent"
|
||||
: "domainVerifiedEvent",
|
||||
ev.domainName,
|
||||
);
|
||||
msg = humanReadableMsg = this.i18nService.t("domainClaimedEvent", ev.domainName);
|
||||
break;
|
||||
case EventType.OrganizationDomain_NotVerified:
|
||||
msg = humanReadableMsg = this.i18nService.t(
|
||||
(await this.configService.getFeatureFlag(FeatureFlag.AccountDeprovisioning))
|
||||
? "domainNotClaimedEvent"
|
||||
: "domainNotVerifiedEvent",
|
||||
ev.domainName,
|
||||
);
|
||||
msg = humanReadableMsg = this.i18nService.t("domainNotClaimedEvent", ev.domainName);
|
||||
break;
|
||||
// Secrets Manager
|
||||
case EventType.Secret_Retrieved:
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import {
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
import { combineLatest, map, Observable, Subject, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@@ -25,7 +16,6 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -83,22 +73,11 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
||||
map((policies) => policies.filter((p) => p.type == PolicyType.ResetPassword)),
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const managingOrg$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.AccountDeprovisioning)
|
||||
.pipe(
|
||||
switchMap((isAccountDeprovisioningEnabled) =>
|
||||
isAccountDeprovisioningEnabled
|
||||
? this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
: of(null),
|
||||
),
|
||||
);
|
||||
const managingOrg$ = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.organizationService.organizations$(userId)),
|
||||
map((organizations) => organizations.find((o) => o.userIsManagedByOrganization === true)),
|
||||
);
|
||||
|
||||
combineLatest([
|
||||
this.organization$,
|
||||
|
||||
@@ -5055,9 +5055,6 @@
|
||||
"singleOrgBlockCreateMessage": {
|
||||
"message": "Your current organization has a policy that does not allow you to join more than one organization. Please contact your organization admins or sign up from a different Bitwarden account."
|
||||
},
|
||||
"singleOrgPolicyWarning": {
|
||||
"message": "Organization members who are not owners or admins and are already a member of another organization will be removed from your organization."
|
||||
},
|
||||
"singleOrgPolicyMemberWarning": {
|
||||
"message": "Non-compliant members will be placed in revoked status until they leave all other organizations. Administrators are exempt and can restore members once compliance is met."
|
||||
},
|
||||
@@ -5887,15 +5884,6 @@
|
||||
"fingerprintPhrase": {
|
||||
"message": "Fingerprint phrase:"
|
||||
},
|
||||
"removeUsers": {
|
||||
"message": "Remove users"
|
||||
},
|
||||
"revokeUsers": {
|
||||
"message": "Revoke users"
|
||||
},
|
||||
"restoreUsers": {
|
||||
"message": "Restore users"
|
||||
},
|
||||
"error": {
|
||||
"message": "Error"
|
||||
},
|
||||
@@ -7837,12 +7825,6 @@
|
||||
"noDomainsSubText": {
|
||||
"message": "Connecting a domain allows members to skip the SSO identifier field during Login with SSO."
|
||||
},
|
||||
"verifyDomain": {
|
||||
"message": "Verify domain"
|
||||
},
|
||||
"reverifyDomain": {
|
||||
"message": "Reverify domain"
|
||||
},
|
||||
"copyDnsTxtRecord": {
|
||||
"message": "Copy DNS TXT record"
|
||||
},
|
||||
@@ -7852,18 +7834,6 @@
|
||||
"dnsTxtRecordInputHint": {
|
||||
"message": "Copy and paste the TXT record into your DNS Provider."
|
||||
},
|
||||
"domainNameInputHint": {
|
||||
"message": "Example: mydomain.com. Subdomains require separate entries to be verified."
|
||||
},
|
||||
"automaticDomainVerification": {
|
||||
"message": "Automatic Domain Verification"
|
||||
},
|
||||
"automaticDomainVerificationProcess": {
|
||||
"message": "Bitwarden will attempt to verify the domain 3 times during the first 72 hours. If the domain can’t be verified, check the DNS record in your host and manually verify. The domain will be removed from your organization in 7 days if it is not verified"
|
||||
},
|
||||
"invalidDomainNameMessage": {
|
||||
"message": "Input is not a valid format. Format: mydomain.com. Subdomains require separate entries to be verified."
|
||||
},
|
||||
"removeDomain": {
|
||||
"message": "Remove domain"
|
||||
},
|
||||
@@ -7876,9 +7846,6 @@
|
||||
"domainSaved": {
|
||||
"message": "Domain saved"
|
||||
},
|
||||
"domainVerified": {
|
||||
"message": "Domain verified"
|
||||
},
|
||||
"duplicateDomainError": {
|
||||
"message": "You can't claim the same domain twice."
|
||||
},
|
||||
@@ -7891,21 +7858,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"domainNotVerified": {
|
||||
"message": "$DOMAIN$ not verified. Check your DNS record.",
|
||||
"placeholders": {
|
||||
"DOMAIN": {
|
||||
"content": "$1",
|
||||
"example": "bitwarden.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domainStatusVerified": {
|
||||
"message": "Verified"
|
||||
},
|
||||
"domainStatusUnverified": {
|
||||
"message": "Unverified"
|
||||
},
|
||||
"domainNameTh": {
|
||||
"message": "Name"
|
||||
},
|
||||
@@ -7939,24 +7891,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"domainVerifiedEvent": {
|
||||
"message": "$DOMAIN$ verified",
|
||||
"placeholders": {
|
||||
"DOMAIN": {
|
||||
"content": "$1",
|
||||
"example": "bitwarden.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domainNotVerifiedEvent": {
|
||||
"message": "$DOMAIN$ not verified",
|
||||
"placeholders": {
|
||||
"DOMAIN": {
|
||||
"content": "$1",
|
||||
"example": "bitwarden.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verificationRequiredForActionSetPinToContinue": {
|
||||
"message": "Verification required for this action. Set a PIN to continue."
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<span bitDialogTitle>
|
||||
<span *ngIf="!data.orgDomain">{{ "newDomain" | i18n }}</span>
|
||||
<span *ngIf="data.orgDomain">
|
||||
{{ ((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain") | i18n }}
|
||||
{{ "claimDomain" | i18n }}
|
||||
</span>
|
||||
|
||||
<span *ngIf="data.orgDomain" class="tw-text-xs tw-text-muted">
|
||||
@@ -15,30 +15,17 @@
|
||||
</span>
|
||||
|
||||
<span *ngIf="data?.orgDomain && !data.orgDomain?.verifiedDate" bitBadge variant="warning">
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusUnderVerification"
|
||||
: "domainStatusUnverified"
|
||||
) | i18n
|
||||
}}
|
||||
{{ "domainStatusUnderVerification" | i18n }}
|
||||
</span>
|
||||
<span *ngIf="data?.orgDomain && data?.orgDomain?.verifiedDate" bitBadge variant="success">
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "domainStatusClaimed" : "domainStatusVerified")
|
||||
| i18n
|
||||
}}
|
||||
{{ "domainStatusClaimed" | i18n }}
|
||||
</span>
|
||||
</span>
|
||||
<div bitDialogContent>
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "domainName" | i18n }}</bit-label>
|
||||
<input bitInput appAutofocus formControlName="domainName" [showErrorsWhenDisabled]="true" />
|
||||
<bit-hint>{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "claimDomainNameInputHint"
|
||||
: "domainNameInputHint"
|
||||
) | i18n
|
||||
}}</bit-hint>
|
||||
<bit-hint>{{ "claimDomainNameInputHint" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field *ngIf="data?.orgDomain">
|
||||
@@ -57,29 +44,18 @@
|
||||
<bit-callout
|
||||
*ngIf="data?.orgDomain && !data?.orgDomain?.verifiedDate"
|
||||
type="info"
|
||||
title="{{
|
||||
(accountDeprovisioningEnabled$ | async)
|
||||
? ('automaticClaimedDomains' | i18n | uppercase)
|
||||
: ('automaticDomainVerification' | i18n)
|
||||
}}"
|
||||
title="{{ 'automaticClaimedDomains' | i18n | uppercase }}"
|
||||
>
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "automaticDomainClaimProcess"
|
||||
: "automaticDomainVerificationProcess"
|
||||
) | i18n
|
||||
}}
|
||||
{{ "automaticDomainClaimProcess" | i18n }}
|
||||
</bit-callout>
|
||||
</div>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||
<span *ngIf="!data?.orgDomain">{{ "next" | i18n }}</span>
|
||||
<span *ngIf="data?.orgDomain && !data?.orgDomain?.verifiedDate">{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain") | i18n
|
||||
}}</span>
|
||||
<span *ngIf="data?.orgDomain?.verifiedDate">{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "reclaimDomain" : "reverifyDomain") | i18n
|
||||
"claimDomain" | i18n
|
||||
}}</span>
|
||||
<span *ngIf="data?.orgDomain?.verifiedDate">{{ "reclaimDomain" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton buttonType="secondary" (click)="dialogRef.close()" type="button">
|
||||
{{ "cancel" | i18n }}
|
||||
|
||||
@@ -2,19 +2,15 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil, Observable, firstValueFrom } from "rxjs";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||
import { OrgDomainServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
||||
import { OrganizationDomainResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain.response";
|
||||
import { OrganizationDomainRequest } from "@bitwarden/common/admin-console/services/organization-domain/requests/organization-domain.request";
|
||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { DialogRef, DIALOG_DATA, DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
@@ -32,7 +28,6 @@ export interface DomainAddEditDialogData {
|
||||
export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
private componentDestroyed$: Subject<void> = new Subject();
|
||||
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
domainForm: FormGroup;
|
||||
|
||||
get domainNameCtrl(): FormControl {
|
||||
@@ -50,20 +45,13 @@ export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
public dialogRef: DialogRef,
|
||||
@Inject(DIALOG_DATA) public data: DomainAddEditDialogData,
|
||||
private formBuilder: FormBuilder,
|
||||
private cryptoFunctionService: CryptoFunctionServiceAbstraction,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private orgDomainApiService: OrgDomainApiServiceAbstraction,
|
||||
private orgDomainService: OrgDomainServiceAbstraction,
|
||||
private validationService: ValidationService,
|
||||
private dialogService: DialogService,
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
) {}
|
||||
|
||||
// Angular Method Implementations
|
||||
|
||||
@@ -73,11 +61,7 @@ export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
"",
|
||||
[
|
||||
Validators.required,
|
||||
domainNameValidator(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? this.i18nService.t("invalidDomainNameClaimMessage")
|
||||
: this.i18nService.t("invalidDomainNameMessage"),
|
||||
),
|
||||
domainNameValidator(this.i18nService.t("invalidDomainNameClaimMessage")),
|
||||
uniqueInArrayValidator(
|
||||
this.data.existingDomainNames,
|
||||
this.i18nService.t("duplicateDomainError"),
|
||||
@@ -223,22 +207,13 @@ export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainClaimed"
|
||||
: "domainVerified",
|
||||
),
|
||||
message: this.i18nService.t("domainClaimed"),
|
||||
});
|
||||
this.dialogRef.close();
|
||||
} else {
|
||||
this.domainNameCtrl.setErrors({
|
||||
errorPassthrough: {
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainNotClaimed"
|
||||
: "domainNotVerified",
|
||||
this.domainNameCtrl.value,
|
||||
),
|
||||
message: this.i18nService.t("domainNotClaimed", this.domainNameCtrl.value),
|
||||
},
|
||||
});
|
||||
// For the case where user opens dialog and reverifies when domain name formControl disabled.
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
</button>
|
||||
</app-header>
|
||||
|
||||
<p
|
||||
bitTypography="body1"
|
||||
class="tw-text-main tw-w-2/5"
|
||||
*ngIf="accountDeprovisioningEnabled$ | async"
|
||||
>
|
||||
<p bitTypography="body1" class="tw-text-main tw-w-2/5">
|
||||
{{ "claimedDomainsDesc" | i18n }}
|
||||
<a
|
||||
bitLink
|
||||
@@ -58,16 +54,10 @@
|
||||
</td>
|
||||
<td bitCell>
|
||||
<span *ngIf="!orgDomain?.verifiedDate" bitBadge variant="warning">{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusUnderVerification"
|
||||
: "domainStatusUnverified"
|
||||
) | i18n
|
||||
"domainStatusUnderVerification" | i18n
|
||||
}}</span>
|
||||
<span *ngIf="orgDomain?.verifiedDate" bitBadge variant="success">{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusClaimed"
|
||||
: "domainStatusVerified"
|
||||
) | i18n
|
||||
"domainStatusClaimed" | i18n
|
||||
}}</span>
|
||||
</td>
|
||||
<td bitCell class="tw-text-muted">
|
||||
@@ -94,10 +84,7 @@
|
||||
type="button"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain")
|
||||
| i18n
|
||||
}}
|
||||
{{ "claimDomain" | i18n }}
|
||||
</button>
|
||||
<button bitMenuItem (click)="deleteDomain(orgDomain.id)" type="button">
|
||||
<span class="tw-text-danger">
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
switchMap,
|
||||
take,
|
||||
takeUntil,
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||
@@ -22,7 +21,6 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -46,7 +44,6 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
|
||||
organizationId: string;
|
||||
orgDomains$: Observable<OrganizationDomainResponse[]>;
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -59,11 +56,7 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
private configService: ConfigService,
|
||||
private policyService: PolicyService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.orgDomains$ = this.orgDomainService.orgDomains$;
|
||||
@@ -85,20 +78,18 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
async load() {
|
||||
await this.orgDomainApiService.getAllByOrgId(this.organizationId);
|
||||
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.AccountDeprovisioning)) {
|
||||
const singleOrgPolicy = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.policies$(userId)),
|
||||
map((policies) =>
|
||||
policies.find(
|
||||
(p) => p.type === PolicyType.SingleOrg && p.organizationId === this.organizationId,
|
||||
),
|
||||
const singleOrgPolicy = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.policies$(userId)),
|
||||
map((policies) =>
|
||||
policies.find(
|
||||
(p) => p.type === PolicyType.SingleOrg && p.organizationId === this.organizationId,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.singleOrgPolicyEnabled = singleOrgPolicy?.enabled ?? false;
|
||||
}
|
||||
),
|
||||
);
|
||||
this.singleOrgPolicyEnabled = singleOrgPolicy?.enabled ?? false;
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
@@ -110,29 +101,30 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
existingDomainNames: this.getExistingDomainNames(),
|
||||
};
|
||||
|
||||
await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning).pipe(
|
||||
withLatestFrom(this.orgDomains$),
|
||||
map(async ([accountDeprovisioningEnabled, organizationDomains]) => {
|
||||
if (
|
||||
accountDeprovisioningEnabled &&
|
||||
const showSingleOrgWarning = await firstValueFrom(
|
||||
this.orgDomains$.pipe(
|
||||
map(
|
||||
(organizationDomains) =>
|
||||
!this.singleOrgPolicyEnabled &&
|
||||
organizationDomains.every((domain) => domain.verifiedDate === null)
|
||||
) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "claim-domain-single-org-warning" },
|
||||
content: { key: "single-org-revoked-user-warning" },
|
||||
cancelButtonText: { key: "cancel" },
|
||||
acceptButtonText: { key: "confirm" },
|
||||
acceptAction: () => this.openAddDomainDialog(domainAddEditDialogData),
|
||||
type: "info",
|
||||
});
|
||||
} else {
|
||||
await this.openAddDomainDialog(domainAddEditDialogData);
|
||||
}
|
||||
}),
|
||||
organizationDomains.every((domain) => domain.verifiedDate === null),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (showSingleOrgWarning) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "claim-domain-single-org-warning" },
|
||||
content: { key: "single-org-revoked-user-warning" },
|
||||
cancelButtonText: { key: "cancel" },
|
||||
acceptButtonText: { key: "confirm" },
|
||||
acceptAction: () => this.openAddDomainDialog(domainAddEditDialogData),
|
||||
type: "info",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.openAddDomainDialog(domainAddEditDialogData);
|
||||
}
|
||||
|
||||
private async openAddDomainDialog(domainAddEditDialogData: DomainAddEditDialogData) {
|
||||
@@ -184,22 +176,13 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainClaimed"
|
||||
: "domainVerified",
|
||||
),
|
||||
message: this.i18nService.t("domainClaimed"),
|
||||
});
|
||||
} else {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainNotClaimed"
|
||||
: "domainNotVerified",
|
||||
domainName,
|
||||
),
|
||||
message: this.i18nService.t("domainNotClaimed", domainName),
|
||||
});
|
||||
// Update this item so the last checked date gets updated.
|
||||
await this.updateOrgDomain(orgDomainId);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { inject, NgModule } from "@angular/core";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { isEnterpriseOrgGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/is-enterprise-org.guard";
|
||||
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
||||
import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-console/organizations/layouts/organization-layout.component";
|
||||
@@ -30,12 +28,7 @@ const routes: Routes = [
|
||||
component: DomainVerificationComponent,
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canManageDomainVerification)],
|
||||
resolve: {
|
||||
titleId: async () => {
|
||||
const configService = inject(ConfigService);
|
||||
return (await configService.getFeatureFlag(FeatureFlag.AccountDeprovisioning))
|
||||
? "claimedDomains"
|
||||
: "domainVerification";
|
||||
},
|
||||
titleId: "claimedDomains",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,10 +31,7 @@
|
||||
<input bitInput type="text" formControlName="ssoIdentifier" />
|
||||
<bit-hint>
|
||||
{{ "ssoIdentifierHintPartOne" | i18n }}
|
||||
<a bitLink routerLink="../domain-verification">{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimedDomains" : "domainVerification")
|
||||
| i18n
|
||||
}}</a>
|
||||
<a bitLink routerLink="../domain-verification">{{ "claimedDomains" | i18n }}</a>
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
Validators,
|
||||
} from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
|
||||
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ControlsOf } from "@bitwarden/angular/types/controls-of";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -33,8 +33,6 @@ import { OrganizationSsoRequest } from "@bitwarden/common/auth/models/request/or
|
||||
import { OrganizationSsoResponse } from "@bitwarden/common/auth/models/response/organization-sso.response";
|
||||
import { SsoConfigView } from "@bitwarden/common/auth/models/view/sso-config.view";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@@ -191,8 +189,6 @@ export class SsoComponent implements OnInit, OnDestroy {
|
||||
return this.ssoConfigForm?.controls?.configType as FormControl;
|
||||
}
|
||||
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private route: ActivatedRoute,
|
||||
@@ -202,13 +198,8 @@ export class SsoComponent implements OnInit, OnDestroy {
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private configService: ConfigService,
|
||||
private toastService: ToastService,
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.enabledCtrl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((enabled) => {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ServerConfig } from "../platform/abstractions/config/server-config";
|
||||
*/
|
||||
export enum FeatureFlag {
|
||||
/* Admin Console Team */
|
||||
AccountDeprovisioning = "pm-10308-account-deprovisioning",
|
||||
VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint",
|
||||
LimitItemDeletion = "pm-15493-restrict-item-deletion-to-can-manage-permission",
|
||||
SsoExternalIdVisibility = "pm-18630-sso-external-id-visibility",
|
||||
@@ -80,7 +79,6 @@ const FALSE = false as boolean;
|
||||
*/
|
||||
export const DefaultFeatureFlagValue = {
|
||||
/* Admin Console Team */
|
||||
[FeatureFlag.AccountDeprovisioning]: FALSE,
|
||||
[FeatureFlag.VerifiedSsoDomainEndpoint]: FALSE,
|
||||
[FeatureFlag.LimitItemDeletion]: FALSE,
|
||||
[FeatureFlag.SsoExternalIdVisibility]: FALSE,
|
||||
|
||||
Reference in New Issue
Block a user