mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-26 12:25:20 +01:00
[PM-10294] Remove FC v1 from Clients (#10422)
* chore: remove fc v1 from org.canEditAnyCollection and update callers, refs PM-10294 * chore: remove fc v1 from collectionView.canEdit and update callers, refs PM-10294 * chore: remove fc v1 from organization.canEditAllCiphers and update callers, refs PM-10294 * chore: remove fc v1 from canDeleteAnyCollection, collection views, update callers, refs PM-10294 * chore: remove fc v1 from canEditUser/GroupAccess, refs PM-10294 * chore: remove fc v1 from canViewCollectionInfo, refs PM-10294 * chore: remove fc v1 from account component, refs PM-10294 * fix: remove fc v1 from collections component, refs PM-10294 * fix: update vault-items component, refs PM-10294 * fix: remove fc v1 from collection-dialog and collections components, refs PM-10294 * chore: remove ConfigService from group-add-edit and account components, refs PM-10294 * chore: change canEditAnyCollection to getter and update callers, refs PM-10294 * chore: change canEditUnmanagedCollections to getter and update callers, refs PM-10294 * chore: change canDeleteAnyCollection to getter and update callers, refs PM-10294 * chore: remove deprecated observable and update comments with v1, refs PM-10294 * chore: remove ununsed ConfigService from collection-dialog component, refs PM-10294 * chore: remove final fc v1 ref for vault-collection-row, refs PM-10294
This commit is contained in:
parent
43da67ee51
commit
471dd3bd7b
@ -19,9 +19,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
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";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -96,9 +94,6 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
private organization$ = this.organizationService
|
||||
.get$(this.organizationId)
|
||||
.pipe(shareReplay({ refCount: true }));
|
||||
private flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
|
||||
protected PermissionMode = PermissionMode;
|
||||
protected ResultType = GroupAddEditDialogResultType;
|
||||
@ -179,27 +174,19 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
protected allowAdminAccessToAllCollectionItems$ = combineLatest([
|
||||
this.organization$,
|
||||
this.flexibleCollectionsV1Enabled$,
|
||||
]).pipe(
|
||||
map(([organization, flexibleCollectionsV1Enabled]) => {
|
||||
if (!flexibleCollectionsV1Enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected allowAdminAccessToAllCollectionItems$ = this.organization$.pipe(
|
||||
map((organization) => {
|
||||
return organization.allowAdminAccessToAllCollectionItems;
|
||||
}),
|
||||
);
|
||||
|
||||
protected canAssignAccessToAnyCollection$ = combineLatest([
|
||||
this.organization$,
|
||||
this.flexibleCollectionsV1Enabled$,
|
||||
this.allowAdminAccessToAllCollectionItems$,
|
||||
]).pipe(
|
||||
map(
|
||||
([org, flexibleCollectionsV1Enabled, allowAdminAccessToAllCollectionItems]) =>
|
||||
org.canEditAnyCollection(flexibleCollectionsV1Enabled) ||
|
||||
([org, allowAdminAccessToAllCollectionItems]) =>
|
||||
org.canEditAnyCollection ||
|
||||
// Manage Groups custom permission cannot edit any collection but they can assign access from this dialog
|
||||
// if permitted by collection management settings
|
||||
(org.permissions.manageGroups && allowAdminAccessToAllCollectionItems),
|
||||
@ -224,7 +211,6 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private dialogService: DialogService,
|
||||
private organizationService: OrganizationService,
|
||||
private configService: ConfigService,
|
||||
private accountService: AccountService,
|
||||
private collectionAdminService: CollectionAdminService,
|
||||
) {
|
||||
@ -242,27 +228,13 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
this.cannotAddSelfToGroup$,
|
||||
this.accountService.activeAccount$,
|
||||
this.organization$,
|
||||
this.flexibleCollectionsV1Enabled$,
|
||||
])
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
([
|
||||
collections,
|
||||
members,
|
||||
group,
|
||||
restrictGroupAccess,
|
||||
activeAccount,
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled,
|
||||
]) => {
|
||||
([collections, members, group, restrictGroupAccess, activeAccount, organization]) => {
|
||||
this.members = members;
|
||||
this.group = group;
|
||||
this.collections = mapToAccessItemViews(
|
||||
collections,
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled,
|
||||
group,
|
||||
);
|
||||
this.collections = mapToAccessItemViews(collections, organization, group);
|
||||
|
||||
if (this.group != undefined) {
|
||||
// Must detect changes so that AccessSelector @Inputs() are aware of the latest
|
||||
@ -384,7 +356,6 @@ function mapToAccessSelections(group: GroupView, items: AccessItemView[]): Acces
|
||||
function mapToAccessItemViews(
|
||||
collections: CollectionAdminView[],
|
||||
organization: Organization,
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
group?: GroupView,
|
||||
): AccessItemView[] {
|
||||
return (
|
||||
@ -396,7 +367,7 @@ function mapToAccessItemViews(
|
||||
type: AccessItemType.Collection,
|
||||
labelName: c.name,
|
||||
listName: c.name,
|
||||
readonly: !c.canEditGroupAccess(organization, flexibleCollectionsV1Enabled),
|
||||
readonly: !c.canEditGroupAccess(organization),
|
||||
readonlyPermission: accessSelection ? convertToPermission(accessSelection) : undefined,
|
||||
};
|
||||
})
|
||||
|
@ -23,8 +23,6 @@ import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permi
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
@ -143,7 +141,6 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
private userService: UserAdminService,
|
||||
private organizationUserService: OrganizationUserService,
|
||||
private dialogService: DialogService,
|
||||
private configService: ConfigService,
|
||||
private accountService: AccountService,
|
||||
organizationService: OrganizationService,
|
||||
) {
|
||||
@ -174,15 +171,8 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
? this.userService.get(this.params.organizationId, this.params.organizationUserId)
|
||||
: of(null);
|
||||
|
||||
this.allowAdminAccessToAllCollectionItems$ = combineLatest([
|
||||
this.organization$,
|
||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1),
|
||||
]).pipe(
|
||||
map(([organization, flexibleCollectionsV1Enabled]) => {
|
||||
if (!flexibleCollectionsV1Enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.allowAdminAccessToAllCollectionItems$ = this.organization$.pipe(
|
||||
map((organization) => {
|
||||
return organization.allowAdminAccessToAllCollectionItems;
|
||||
}),
|
||||
);
|
||||
@ -208,18 +198,13 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
const flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
|
||||
this.canAssignAccessToAnyCollection$ = combineLatest([
|
||||
this.organization$,
|
||||
flexibleCollectionsV1Enabled$,
|
||||
this.allowAdminAccessToAllCollectionItems$,
|
||||
]).pipe(
|
||||
map(
|
||||
([org, flexibleCollectionsV1Enabled, allowAdminAccessToAllCollectionItems]) =>
|
||||
org.canEditAnyCollection(flexibleCollectionsV1Enabled) ||
|
||||
([org, allowAdminAccessToAllCollectionItems]) =>
|
||||
org.canEditAnyCollection ||
|
||||
// Manage Users custom permission cannot edit any collection but they can assign access from this dialog
|
||||
// if permitted by collection management settings
|
||||
(org.permissions.manageUsers && allowAdminAccessToAllCollectionItems),
|
||||
@ -231,11 +216,9 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
collections: this.collectionAdminService.getAll(this.params.organizationId),
|
||||
userDetails: userDetails$,
|
||||
groups: groups$,
|
||||
flexibleCollectionsV1Enabled: flexibleCollectionsV1Enabled$,
|
||||
})
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
({ organization, collections, userDetails, groups, flexibleCollectionsV1Enabled }) => {
|
||||
.subscribe(({ organization, collections, userDetails, groups }) => {
|
||||
this.setFormValidators(organization);
|
||||
|
||||
// Groups tab: populate available groups
|
||||
@ -249,7 +232,6 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
mapCollectionToAccessItemView(
|
||||
c,
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled,
|
||||
userDetails == null
|
||||
? undefined
|
||||
: c.users.find((access) => access.id === userDetails.id),
|
||||
@ -262,18 +244,11 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
);
|
||||
|
||||
if (userDetails != null) {
|
||||
this.loadOrganizationUser(
|
||||
userDetails,
|
||||
groups,
|
||||
collections,
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled,
|
||||
);
|
||||
this.loadOrganizationUser(userDetails, groups, collections, organization);
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private setFormValidators(organization: Organization) {
|
||||
@ -297,7 +272,6 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
groups: GroupView[],
|
||||
collections: CollectionAdminView[],
|
||||
organization: Organization,
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
) {
|
||||
if (!userDetails) {
|
||||
throw new Error("Could not find user to edit.");
|
||||
@ -341,13 +315,7 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
// Populate additional collection access via groups (rendered as separate rows from user access)
|
||||
this.collectionAccessItems = this.collectionAccessItems.concat(
|
||||
collectionsFromGroups.map(({ collection, accessSelection, group }) =>
|
||||
mapCollectionToAccessItemView(
|
||||
collection,
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled,
|
||||
accessSelection,
|
||||
group,
|
||||
),
|
||||
mapCollectionToAccessItemView(collection, organization, accessSelection, group),
|
||||
),
|
||||
);
|
||||
|
||||
@ -621,7 +589,6 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
function mapCollectionToAccessItemView(
|
||||
collection: CollectionAdminView,
|
||||
organization: Organization,
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
accessSelection?: CollectionAccessSelectionView,
|
||||
group?: GroupView,
|
||||
): AccessItemView {
|
||||
@ -630,9 +597,7 @@ function mapCollectionToAccessItemView(
|
||||
id: group ? `${collection.id}-${group.id}` : collection.id,
|
||||
labelName: collection.name,
|
||||
listName: collection.name,
|
||||
readonly:
|
||||
group !== undefined ||
|
||||
!collection.canEditUserAccess(organization, flexibleCollectionsV1Enabled),
|
||||
readonly: group !== undefined || !collection.canEditUserAccess(organization),
|
||||
readonlyPermission: accessSelection ? convertToPermission(accessSelection) : undefined,
|
||||
viaGroupName: group?.name,
|
||||
};
|
||||
|
@ -56,7 +56,7 @@
|
||||
>
|
||||
<h1 bitTypography="h1" class="tw-mt-16 tw-pb-2.5">{{ "collectionManagement" | i18n }}</h1>
|
||||
<p bitTypography="body1">{{ "collectionManagementDesc" | i18n }}</p>
|
||||
<bit-form-control *ngIf="flexibleCollectionsV1Enabled$ | async">
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "allowAdminAccessToAllCollectionItemsDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="allowAdminAccessToAllCollectionItems" />
|
||||
</bit-form-control>
|
||||
|
@ -10,8 +10,6 @@ import { OrganizationCollectionManagementUpdateRequest } from "@bitwarden/common
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { OrganizationUpdateRequest } from "@bitwarden/common/admin-console/models/request/organization-update.request";
|
||||
import { OrganizationResponse } from "@bitwarden/common/admin-console/models/response/organization.response";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -40,10 +38,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
org: OrganizationResponse;
|
||||
taxFormPromise: Promise<unknown>;
|
||||
|
||||
flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
|
||||
// FormGroup validators taken from server Organization domain object
|
||||
protected formGroup = this.formBuilder.group({
|
||||
orgName: this.formBuilder.control(
|
||||
@ -83,7 +77,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private dialogService: DialogService,
|
||||
private formBuilder: FormBuilder,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
|
@ -80,13 +80,9 @@
|
||||
<span *ngIf="!organization.useGroups">{{
|
||||
"grantCollectionAccessMembersOnly" | i18n
|
||||
}}</span>
|
||||
<span
|
||||
*ngIf="
|
||||
(flexibleCollectionsV1Enabled$ | async) &&
|
||||
organization.allowAdminAccessToAllCollectionItems
|
||||
"
|
||||
>{{ " " + ("adminCollectionAccess" | i18n) }}</span
|
||||
>
|
||||
<span *ngIf="organization.allowAdminAccessToAllCollectionItems">
|
||||
{{ " " + ("adminCollectionAccess" | i18n) }}
|
||||
</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div
|
||||
|
@ -17,8 +17,6 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||
import { OrganizationUserUserDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses/organization-user.response";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
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";
|
||||
@ -77,10 +75,6 @@ export enum CollectionDialogAction {
|
||||
templateUrl: "collection-dialog.component.html",
|
||||
})
|
||||
export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
protected flexibleCollectionsV1Enabled$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1)
|
||||
.pipe(first());
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
protected organizations$: Observable<Organization[]>;
|
||||
|
||||
@ -113,7 +107,6 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private organizationUserService: OrganizationUserService,
|
||||
private configService: ConfigService,
|
||||
private dialogService: DialogService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
) {
|
||||
@ -163,11 +156,9 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
groups: groups$,
|
||||
// Collection(s) needed to map readonlypermission for (potential) access selector disabled state
|
||||
users: this.organizationUserService.getAllUsers(orgId, { includeCollections: true }),
|
||||
flexibleCollectionsV1: this.flexibleCollectionsV1Enabled$,
|
||||
})
|
||||
.pipe(takeUntil(this.formGroup.controls.selectedOrg.valueChanges), takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
({ organization, collections: allCollections, groups, users, flexibleCollectionsV1 }) => {
|
||||
.subscribe(({ organization, collections: allCollections, groups, users }) => {
|
||||
this.organization = organization;
|
||||
this.accessItems = [].concat(
|
||||
groups.map((group) => mapGroupToAccessItemView(group, this.collectionId)),
|
||||
@ -214,9 +205,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
parent: parentName,
|
||||
access: accessSelections,
|
||||
});
|
||||
this.showDeleteButton =
|
||||
!this.dialogReadonly &&
|
||||
this.collection.canDelete(organization, flexibleCollectionsV1);
|
||||
this.showDeleteButton = !this.dialogReadonly && this.collection.canDelete(organization);
|
||||
} else {
|
||||
const parent = this.nestOptions.find((c) => c.id === this.params.parentCollectionId);
|
||||
const currentOrgUserId = users.data.find(
|
||||
@ -239,7 +228,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
if (flexibleCollectionsV1 && !organization.allowAdminAccessToAllCollectionItems) {
|
||||
if (!organization.allowAdminAccessToAllCollectionItems) {
|
||||
this.formGroup.controls.access.addValidators(validateCanManagePermission);
|
||||
} else {
|
||||
this.formGroup.controls.access.removeValidators(validateCanManagePermission);
|
||||
@ -249,9 +238,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.handleFormGroupReadonly(this.dialogReadonly);
|
||||
|
||||
this.loading = false;
|
||||
this.showAddAccessWarning = this.handleAddAccessWarning(flexibleCollectionsV1);
|
||||
},
|
||||
);
|
||||
this.showAddAccessWarning = this.handleAddAccessWarning();
|
||||
});
|
||||
}
|
||||
|
||||
protected get collectionId() {
|
||||
@ -361,9 +349,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
private handleAddAccessWarning(flexibleCollectionsV1: boolean): boolean {
|
||||
private handleAddAccessWarning(): boolean {
|
||||
if (
|
||||
flexibleCollectionsV1 &&
|
||||
!this.organization?.allowAdminAccessToAllCollectionItems &&
|
||||
this.params.isAddAccessCollection
|
||||
) {
|
||||
|
@ -34,7 +34,6 @@ export class VaultCollectionRowComponent {
|
||||
@Input() organizations: Organization[];
|
||||
@Input() groups: GroupView[];
|
||||
@Input() showPermissionsColumn: boolean;
|
||||
@Input() flexibleCollectionsV1Enabled: boolean;
|
||||
@Input() restrictProviderAccess: boolean;
|
||||
|
||||
@Output() onEvent = new EventEmitter<VaultItemEvent>();
|
||||
@ -57,10 +56,6 @@ export class VaultCollectionRowComponent {
|
||||
}
|
||||
|
||||
get showAddAccess() {
|
||||
if (!this.flexibleCollectionsV1Enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.collection.id == Unassigned) {
|
||||
return false;
|
||||
}
|
||||
@ -71,7 +66,7 @@ export class VaultCollectionRowComponent {
|
||||
return (
|
||||
!this.organization?.allowAdminAccessToAllCollectionItems &&
|
||||
this.collection.unmanaged &&
|
||||
this.organization?.canEditUnmanagedCollections()
|
||||
this.organization?.canEditUnmanagedCollections
|
||||
);
|
||||
}
|
||||
|
||||
@ -114,10 +109,6 @@ export class VaultCollectionRowComponent {
|
||||
}
|
||||
|
||||
protected get showCheckbox() {
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
return this.collection?.id !== Unassigned;
|
||||
}
|
||||
|
||||
return this.canDeleteCollection;
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,6 @@
|
||||
[canDeleteCollection]="canDeleteCollection(item.collection)"
|
||||
[canEditCollection]="canEditCollection(item.collection)"
|
||||
[canViewCollectionInfo]="canViewCollectionInfo(item.collection)"
|
||||
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled"
|
||||
[restrictProviderAccess]="restrictProviderAccess"
|
||||
[checked]="selection.isSelected(item)"
|
||||
(checkedToggled)="selection.toggle(item)"
|
||||
|
@ -44,7 +44,6 @@ export class VaultItemsComponent {
|
||||
@Input() showBulkAddToCollections = false;
|
||||
@Input() showPermissionsColumn = false;
|
||||
@Input() viewingOrgVault: boolean;
|
||||
@Input({ required: true }) flexibleCollectionsV1Enabled = false;
|
||||
@Input() addAccessStatus: number;
|
||||
@Input() addAccessToggle: boolean;
|
||||
@Input() restrictProviderAccess: boolean;
|
||||
@ -120,7 +119,7 @@ export class VaultItemsComponent {
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
|
||||
return collection.canEdit(organization, this.flexibleCollectionsV1Enabled);
|
||||
return collection.canEdit(organization);
|
||||
}
|
||||
|
||||
protected canDeleteCollection(collection: CollectionView): boolean {
|
||||
@ -131,12 +130,12 @@ export class VaultItemsComponent {
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
|
||||
return collection.canDelete(organization, this.flexibleCollectionsV1Enabled);
|
||||
return collection.canDelete(organization);
|
||||
}
|
||||
|
||||
protected canViewCollectionInfo(collection: CollectionView) {
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
return collection.canViewCollectionInfo(organization, this.flexibleCollectionsV1Enabled);
|
||||
return collection.canViewCollectionInfo(organization);
|
||||
}
|
||||
|
||||
protected toggleAll() {
|
||||
@ -214,11 +213,7 @@ export class VaultItemsComponent {
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === cipher.organizationId);
|
||||
return (
|
||||
(organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) &&
|
||||
this.viewingOrgVault) ||
|
||||
(organization.canEditAllCiphers(this.restrictProviderAccess) && this.viewingOrgVault) ||
|
||||
cipher.edit
|
||||
);
|
||||
}
|
||||
@ -230,21 +225,12 @@ export class VaultItemsComponent {
|
||||
|
||||
this.selection.clear();
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
// Every item except for the Unassigned collection is selectable, individual bulk actions check the user's permission
|
||||
this.editableItems = items.filter(
|
||||
(item) =>
|
||||
item.cipher !== undefined ||
|
||||
(item.collection !== undefined && item.collection.id !== Unassigned),
|
||||
);
|
||||
} else {
|
||||
// only collections the user can delete are selectable
|
||||
this.editableItems = items.filter(
|
||||
(item) =>
|
||||
item.cipher !== undefined ||
|
||||
(item.collection !== undefined && this.canDeleteCollection(item.collection)),
|
||||
);
|
||||
}
|
||||
|
||||
this.dataSource.data = items;
|
||||
}
|
||||
@ -293,10 +279,7 @@ export class VaultItemsComponent {
|
||||
const organization = this.allOrganizations.find((o) => o.id === orgId);
|
||||
|
||||
const canEditOrManageAllCiphers =
|
||||
organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) && this.viewingOrgVault;
|
||||
organization?.canEditAllCiphers(this.restrictProviderAccess) && this.viewingOrgVault;
|
||||
|
||||
const collectionNotSelected =
|
||||
this.selection.selected.filter((item) => item.collection).length === 0;
|
||||
@ -317,9 +300,7 @@ export class VaultItemsComponent {
|
||||
|
||||
const canEditOrManageAllCiphers =
|
||||
organizations.length > 0 &&
|
||||
organizations.every((org) =>
|
||||
org?.canEditAllCiphers(this.flexibleCollectionsV1Enabled, this.restrictProviderAccess),
|
||||
);
|
||||
organizations.every((org) => org?.canEditAllCiphers(this.restrictProviderAccess));
|
||||
|
||||
const canDeleteCollections = this.selection.selected
|
||||
.filter((item) => item.collection)
|
||||
|
@ -41,61 +41,44 @@ export class CollectionAdminView extends CollectionView {
|
||||
/**
|
||||
* Returns true if the user can edit a collection (including user and group access) from the Admin Console.
|
||||
*/
|
||||
override canEdit(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
override canEdit(org: Organization): boolean {
|
||||
return (
|
||||
org?.canEditAnyCollection(flexibleCollectionsV1Enabled) ||
|
||||
(flexibleCollectionsV1Enabled && this.unmanaged && org?.canEditUnmanagedCollections()) ||
|
||||
super.canEdit(org, flexibleCollectionsV1Enabled)
|
||||
org?.canEditAnyCollection ||
|
||||
(this.unmanaged && org?.canEditUnmanagedCollections) ||
|
||||
super.canEdit(org)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user can delete a collection from the Admin Console.
|
||||
*/
|
||||
override canDelete(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
return (
|
||||
org?.canDeleteAnyCollection(flexibleCollectionsV1Enabled) ||
|
||||
super.canDelete(org, flexibleCollectionsV1Enabled)
|
||||
);
|
||||
override canDelete(org: Organization): boolean {
|
||||
return org?.canDeleteAnyCollection || super.canDelete(org);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user can modify user access to this collection
|
||||
*/
|
||||
canEditUserAccess(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
const allowAdminAccessToAllCollectionItems =
|
||||
!flexibleCollectionsV1Enabled || org.allowAdminAccessToAllCollectionItems;
|
||||
|
||||
canEditUserAccess(org: Organization): boolean {
|
||||
return (
|
||||
(org.permissions.manageUsers && allowAdminAccessToAllCollectionItems) ||
|
||||
this.canEdit(org, flexibleCollectionsV1Enabled)
|
||||
(org.permissions.manageUsers && org.allowAdminAccessToAllCollectionItems) || this.canEdit(org)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user can modify group access to this collection
|
||||
*/
|
||||
canEditGroupAccess(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
const allowAdminAccessToAllCollectionItems =
|
||||
!flexibleCollectionsV1Enabled || org.allowAdminAccessToAllCollectionItems;
|
||||
|
||||
canEditGroupAccess(org: Organization): boolean {
|
||||
return (
|
||||
(org.permissions.manageGroups && allowAdminAccessToAllCollectionItems) ||
|
||||
this.canEdit(org, flexibleCollectionsV1Enabled)
|
||||
(org.permissions.manageGroups && org.allowAdminAccessToAllCollectionItems) ||
|
||||
this.canEdit(org)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user can view collection info and access in a read-only state from the Admin Console
|
||||
*/
|
||||
override canViewCollectionInfo(
|
||||
org: Organization | undefined,
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
): boolean {
|
||||
if (!flexibleCollectionsV1Enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
override canViewCollectionInfo(org: Organization | undefined): boolean {
|
||||
if (this.isUnassignedCollection) {
|
||||
return false;
|
||||
}
|
||||
|
@ -54,10 +54,6 @@ export class BulkDeleteDialogComponent {
|
||||
collections: CollectionView[];
|
||||
unassignedCiphers: string[];
|
||||
|
||||
private flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
|
||||
private restrictProviderAccess$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -96,13 +92,9 @@ export class BulkDeleteDialogComponent {
|
||||
deletePromises.push(this.deleteCiphersAdmin(this.unassignedCiphers));
|
||||
}
|
||||
if (this.cipherIds.length) {
|
||||
const flexibleCollectionsV1Enabled = await firstValueFrom(this.flexibleCollectionsV1Enabled$);
|
||||
const restrictProviderAccess = await firstValueFrom(this.restrictProviderAccess$);
|
||||
|
||||
if (
|
||||
!this.organization ||
|
||||
!this.organization.canEditAllCiphers(flexibleCollectionsV1Enabled, restrictProviderAccess)
|
||||
) {
|
||||
if (!this.organization || !this.organization.canEditAllCiphers(restrictProviderAccess)) {
|
||||
deletePromises.push(this.deleteCiphers());
|
||||
} else {
|
||||
deletePromises.push(this.deleteCiphersAdmin(this.cipherIds));
|
||||
@ -134,12 +126,8 @@ export class BulkDeleteDialogComponent {
|
||||
};
|
||||
|
||||
private async deleteCiphers(): Promise<any> {
|
||||
const flexibleCollectionsV1Enabled = await firstValueFrom(this.flexibleCollectionsV1Enabled$);
|
||||
const restrictProviderAccess = await firstValueFrom(this.restrictProviderAccess$);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(
|
||||
flexibleCollectionsV1Enabled,
|
||||
restrictProviderAccess,
|
||||
);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(restrictProviderAccess);
|
||||
if (this.permanent) {
|
||||
await this.cipherService.deleteManyWithServer(this.cipherIds, asAdmin);
|
||||
} else {
|
||||
@ -157,12 +145,9 @@ export class BulkDeleteDialogComponent {
|
||||
}
|
||||
|
||||
private async deleteCollections(): Promise<any> {
|
||||
const flexibleCollectionsV1Enabled = await firstValueFrom(this.flexibleCollectionsV1Enabled$);
|
||||
// From org vault
|
||||
if (this.organization) {
|
||||
if (
|
||||
this.collections.some((c) => !c.canDelete(this.organization, flexibleCollectionsV1Enabled))
|
||||
) {
|
||||
if (this.collections.some((c) => !c.canDelete(this.organization))) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
@ -179,7 +164,7 @@ export class BulkDeleteDialogComponent {
|
||||
const deletePromises: Promise<any>[] = [];
|
||||
for (const organization of this.organizations) {
|
||||
const orgCollections = this.collections.filter((o) => o.organizationId === organization.id);
|
||||
if (orgCollections.some((c) => !c.canDelete(organization, flexibleCollectionsV1Enabled))) {
|
||||
if (orgCollections.some((c) => !c.canDelete(organization))) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -32,13 +32,7 @@
|
||||
[(ngModel)]="$any(c).checked"
|
||||
name="Collection[{{ i }}].Checked"
|
||||
appStopProp
|
||||
[disabled]="
|
||||
!c.canEditItems(
|
||||
this.organization,
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess
|
||||
)
|
||||
"
|
||||
[disabled]="!c.canEditItems(this.organization, this.restrictProviderAccess)"
|
||||
/>
|
||||
{{ c.name }}
|
||||
</td>
|
||||
|
@ -50,13 +50,7 @@ export class CollectionsComponent extends BaseCollectionsComponent implements On
|
||||
}
|
||||
|
||||
check(c: CollectionView, select?: boolean) {
|
||||
if (
|
||||
!c.canEditItems(
|
||||
this.organization,
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!c.canEditItems(this.organization, this.restrictProviderAccess)) {
|
||||
return;
|
||||
}
|
||||
(c as any).checked = select == null ? !(c as any).checked : select;
|
||||
|
@ -84,17 +84,12 @@ export class VaultHeaderComponent implements OnInit {
|
||||
/** Emits an event when the delete collection button is clicked in the header */
|
||||
@Output() onDeleteCollection = new EventEmitter<void>();
|
||||
|
||||
private flexibleCollectionsV1Enabled = false;
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1),
|
||||
);
|
||||
this.extensionRefreshEnabled = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.ExtensionRefresh),
|
||||
);
|
||||
@ -180,7 +175,7 @@ export class VaultHeaderComponent implements OnInit {
|
||||
const organization = this.organizations.find(
|
||||
(o) => o.id === this.collection?.node.organizationId,
|
||||
);
|
||||
return this.collection.node.canEdit(organization, this.flexibleCollectionsV1Enabled);
|
||||
return this.collection.node.canEdit(organization);
|
||||
}
|
||||
|
||||
async editCollection(tab: CollectionDialogTabType): Promise<void> {
|
||||
@ -198,7 +193,7 @@ export class VaultHeaderComponent implements OnInit {
|
||||
(o) => o.id === this.collection?.node.organizationId,
|
||||
);
|
||||
|
||||
return this.collection.node.canDelete(organization, this.flexibleCollectionsV1Enabled);
|
||||
return this.collection.node.canDelete(organization);
|
||||
}
|
||||
|
||||
deleteCollection() {
|
||||
|
@ -56,7 +56,6 @@
|
||||
[showAdminActions]="false"
|
||||
[showBulkAddToCollections]="vaultBulkManagementActionEnabled$ | async"
|
||||
(onEvent)="onVaultItemsEvent($event)"
|
||||
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled$ | async"
|
||||
[vaultBulkManagementActionEnabled]="vaultBulkManagementActionEnabled$ | async"
|
||||
>
|
||||
</app-vault-items>
|
||||
|
@ -158,9 +158,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected selectedCollection: TreeNode<CollectionView> | undefined;
|
||||
protected canCreateCollections = false;
|
||||
protected currentSearchText$: Observable<string>;
|
||||
protected flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
protected vaultBulkManagementActionEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.VaultBulkManagementAction,
|
||||
);
|
||||
@ -552,7 +549,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async shareCipher(cipher: CipherView) {
|
||||
if ((await this.flexibleCollectionsV1Enabled()) && cipher.organizationId != null) {
|
||||
if (cipher.organizationId != null) {
|
||||
// You cannot move ciphers between organizations
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
@ -712,8 +709,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
async deleteCollection(collection: CollectionView): Promise<void> {
|
||||
const organization = await this.organizationService.get(collection.organizationId);
|
||||
const flexibleCollectionsV1Enabled = await firstValueFrom(this.flexibleCollectionsV1Enabled$);
|
||||
if (!collection.canDelete(organization, flexibleCollectionsV1Enabled)) {
|
||||
if (!collection.canDelete(organization)) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -811,7 +807,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((await this.flexibleCollectionsV1Enabled()) && !c.edit) {
|
||||
if (!c.edit) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -834,7 +830,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async bulkRestore(ciphers: CipherView[]) {
|
||||
if ((await this.flexibleCollectionsV1Enabled()) && ciphers.some((c) => !c.edit)) {
|
||||
if (ciphers.some((c) => !c.edit)) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -887,7 +883,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((await this.flexibleCollectionsV1Enabled()) && !c.edit) {
|
||||
if (!c.edit) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -936,19 +932,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
const flexibleCollectionsV1Enabled = await this.flexibleCollectionsV1Enabled();
|
||||
|
||||
const canDeleteCollections =
|
||||
collections == null ||
|
||||
collections.every((c) =>
|
||||
c.canDelete(
|
||||
organizations.find((o) => o.id == c.organizationId),
|
||||
flexibleCollectionsV1Enabled,
|
||||
),
|
||||
);
|
||||
collections.every((c) => c.canDelete(organizations.find((o) => o.id == c.organizationId)));
|
||||
const canDeleteCiphers = ciphers == null || ciphers.every((c) => c.edit);
|
||||
|
||||
if (flexibleCollectionsV1Enabled && (!canDeleteCollections || !canDeleteCiphers)) {
|
||||
if (!canDeleteCollections || !canDeleteCiphers) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -1052,10 +1041,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(await this.flexibleCollectionsV1Enabled()) &&
|
||||
ciphers.some((c) => c.organizationId != null)
|
||||
) {
|
||||
if (ciphers.some((c) => c.organizationId != null)) {
|
||||
// You cannot move ciphers between organizations
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
@ -1099,10 +1085,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return true;
|
||||
}
|
||||
|
||||
const flexibleCollectionsV1Enabled = await this.flexibleCollectionsV1Enabled();
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === cipher.organizationId);
|
||||
return organization.canEditAllCiphers(flexibleCollectionsV1Enabled, false);
|
||||
return organization.canEditAllCiphers(false);
|
||||
}
|
||||
|
||||
private go(queryParams: any = null) {
|
||||
@ -1131,10 +1115,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
message: this.i18nService.t("missingPermissions"),
|
||||
});
|
||||
}
|
||||
|
||||
private flexibleCollectionsV1Enabled() {
|
||||
return firstValueFrom(this.flexibleCollectionsV1Enabled$);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,12 +82,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
}
|
||||
|
||||
protected loadCollections() {
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return super.loadCollections();
|
||||
}
|
||||
return Promise.resolve(this.collections);
|
||||
@ -98,10 +93,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
const firstCipherCheck = await super.loadCipher();
|
||||
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) &&
|
||||
!this.organization.canEditAllCiphers(this.restrictProviderAccess) &&
|
||||
firstCipherCheck != null
|
||||
) {
|
||||
return firstCipherCheck;
|
||||
@ -116,24 +108,14 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
}
|
||||
|
||||
protected encryptCipher() {
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return super.encryptCipher();
|
||||
}
|
||||
return this.cipherService.encrypt(this.cipher, null, null, this.originalCipher);
|
||||
}
|
||||
|
||||
protected async deleteCipher() {
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return super.deleteCipher();
|
||||
}
|
||||
return this.cipher.isDeleted
|
||||
|
@ -28,7 +28,6 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
viewOnly = false;
|
||||
organization: Organization;
|
||||
|
||||
private flexibleCollectionsV1Enabled = false;
|
||||
private restrictProviderAccess = false;
|
||||
|
||||
constructor(
|
||||
@ -60,9 +59,6 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
|
||||
async ngOnInit() {
|
||||
await super.ngOnInit();
|
||||
this.flexibleCollectionsV1Enabled = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1),
|
||||
);
|
||||
this.restrictProviderAccess = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.RestrictProviderAccess),
|
||||
);
|
||||
@ -70,10 +66,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
|
||||
protected async reupload(attachment: AttachmentView) {
|
||||
if (
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) &&
|
||||
this.organization.canEditAllCiphers(this.restrictProviderAccess) &&
|
||||
this.showFixOldAttachments(attachment)
|
||||
) {
|
||||
await super.reuploadCipherAttachment(attachment, true);
|
||||
@ -81,12 +74,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
}
|
||||
|
||||
protected async loadCipher() {
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return await super.loadCipher();
|
||||
}
|
||||
const response = await this.apiService.getCipherAdmin(this.cipherId);
|
||||
@ -97,20 +85,12 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
return this.cipherService.saveAttachmentWithServer(
|
||||
this.cipherDomain,
|
||||
file,
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
),
|
||||
this.organization.canEditAllCiphers(this.restrictProviderAccess),
|
||||
);
|
||||
}
|
||||
|
||||
protected deleteCipherAttachment(attachmentId: string) {
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (!this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return super.deleteCipherAttachment(attachmentId);
|
||||
}
|
||||
return this.apiService.deleteCipherAttachmentAdmin(this.cipherId, attachmentId);
|
||||
@ -118,11 +98,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
|
||||
protected showFixOldAttachments(attachment: AttachmentView) {
|
||||
return (
|
||||
attachment.key == null &&
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
attachment.key == null && this.organization.canEditAllCiphers(this.restrictProviderAccess)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -61,10 +61,7 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
||||
protected async loadCipher() {
|
||||
// if cipher is unassigned use apiService. We can see this by looking at this.collectionIds
|
||||
if (
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) &&
|
||||
!this.organization.canEditAllCiphers(this.restrictProviderAccess) &&
|
||||
this.collectionIds.length !== 0
|
||||
) {
|
||||
return await super.loadCipher();
|
||||
@ -89,10 +86,7 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
||||
|
||||
protected saveCollections() {
|
||||
if (
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
) ||
|
||||
this.organization.canEditAllCiphers(this.restrictProviderAccess) ||
|
||||
this.collectionIds.length === 0
|
||||
) {
|
||||
const request = new CipherCollectionsRequest(this.cipherDomain.collectionIds);
|
||||
|
@ -87,7 +87,6 @@ export class VaultHeaderComponent implements OnInit {
|
||||
protected CollectionDialogTabType = CollectionDialogTabType;
|
||||
protected organizations$ = this.organizationService.organizations$;
|
||||
|
||||
protected flexibleCollectionsV1Enabled = false;
|
||||
protected restrictProviderAccessFlag = false;
|
||||
|
||||
constructor(
|
||||
@ -100,9 +99,6 @@ export class VaultHeaderComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1),
|
||||
);
|
||||
this.restrictProviderAccessFlag = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -195,7 +191,7 @@ export class VaultHeaderComponent implements OnInit {
|
||||
}
|
||||
|
||||
// Otherwise, check if we can edit the specified collection
|
||||
return this.collection.node.canEdit(this.organization, this.flexibleCollectionsV1Enabled);
|
||||
return this.collection.node.canEdit(this.organization);
|
||||
}
|
||||
|
||||
addCipher() {
|
||||
@ -225,14 +221,11 @@ export class VaultHeaderComponent implements OnInit {
|
||||
}
|
||||
|
||||
// Otherwise, check if we can delete the specified collection
|
||||
return this.collection.node.canDelete(this.organization, this.flexibleCollectionsV1Enabled);
|
||||
return this.collection.node.canDelete(this.organization);
|
||||
}
|
||||
|
||||
get canViewCollectionInfo(): boolean {
|
||||
return this.collection.node.canViewCollectionInfo(
|
||||
this.organization,
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
);
|
||||
return this.collection.node.canViewCollectionInfo(this.organization);
|
||||
}
|
||||
|
||||
get canCreateCollection(): boolean {
|
||||
|
@ -68,39 +68,12 @@
|
||||
[showBulkEditCollectionAccess]="true"
|
||||
[showBulkAddToCollections]="true"
|
||||
[viewingOrgVault]="true"
|
||||
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled"
|
||||
[addAccessStatus]="addAccessStatus$ | async"
|
||||
[addAccessToggle]="showAddAccessToggle"
|
||||
[restrictProviderAccess]="restrictProviderAccessEnabled"
|
||||
>
|
||||
</app-vault-items>
|
||||
<ng-container *ngIf="!flexibleCollectionsV1Enabled">
|
||||
<div
|
||||
class="tw-mt-6 tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-start"
|
||||
*ngIf="showMissingCollectionPermissionMessage"
|
||||
>
|
||||
<bit-icon [icon]="noItemIcon" aria-hidden="true"></bit-icon>
|
||||
<p>{{ "noPermissionToViewAllCollectionItems" | i18n }}</p>
|
||||
</div>
|
||||
<div
|
||||
class="tw-mt-6 tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-start"
|
||||
*ngIf="isEmpty && !showMissingCollectionPermissionMessage && !performingInitialLoad"
|
||||
>
|
||||
<bit-icon [icon]="noItemIcon" aria-hidden="true"></bit-icon>
|
||||
<p>{{ "noItemsInList" | i18n }}</p>
|
||||
<button
|
||||
type="button"
|
||||
buttonType="primary"
|
||||
bitButton
|
||||
(click)="addCipher()"
|
||||
*ngIf="filter.type !== 'trash' && filter.collectionId !== Unassigned"
|
||||
>
|
||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
||||
{{ "newItem" | i18n }}
|
||||
</button>
|
||||
</div></ng-container
|
||||
>
|
||||
<ng-container *ngIf="flexibleCollectionsV1Enabled && !performingInitialLoad && isEmpty">
|
||||
<ng-container *ngIf="!performingInitialLoad && isEmpty">
|
||||
<bit-no-items *ngIf="!showCollectionAccessRestricted">
|
||||
<span slot="title" class="tw-mt-4 tw-block">{{ "noItemsInList" | i18n }}</span>
|
||||
<button
|
||||
@ -116,15 +89,8 @@
|
||||
</bit-no-items>
|
||||
<collection-access-restricted
|
||||
*ngIf="showCollectionAccessRestricted"
|
||||
[canEditCollection]="
|
||||
selectedCollection?.node?.canEdit(organization, flexibleCollectionsV1Enabled)
|
||||
"
|
||||
[canViewCollectionInfo]="
|
||||
selectedCollection?.node?.canViewCollectionInfo(
|
||||
organization,
|
||||
flexibleCollectionsV1Enabled
|
||||
)
|
||||
"
|
||||
[canEditCollection]="selectedCollection?.node?.canEdit(organization)"
|
||||
[canViewCollectionInfo]="selectedCollection?.node?.canViewCollectionInfo(organization)"
|
||||
(viewCollectionClicked)="
|
||||
editCollection(selectedCollection.node, $event.tab, $event.readonly)
|
||||
"
|
||||
|
@ -150,12 +150,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected collections: CollectionAdminView[];
|
||||
protected selectedCollection: TreeNode<CollectionAdminView> | undefined;
|
||||
protected isEmpty: boolean;
|
||||
/**
|
||||
* Used to show an old missing permission message for custom users with DeleteAnyCollection
|
||||
* @deprecated Replaced with showCollectionAccessRestricted$ and this should be removed after flexible collections V1
|
||||
* is released
|
||||
*/
|
||||
protected showMissingCollectionPermissionMessage: boolean;
|
||||
protected showCollectionAccessRestricted: boolean;
|
||||
protected currentSearchText$: Observable<string>;
|
||||
/**
|
||||
@ -164,16 +158,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
protected editableCollections$: Observable<CollectionAdminView[]>;
|
||||
protected allCollectionsWithoutUnassigned$: Observable<CollectionAdminView[]>;
|
||||
private _flexibleCollectionsV1FlagEnabled: boolean;
|
||||
|
||||
protected get flexibleCollectionsV1Enabled(): boolean {
|
||||
return this._flexibleCollectionsV1FlagEnabled;
|
||||
}
|
||||
protected orgRevokedUsers: OrganizationUserUserDetailsResponse[];
|
||||
|
||||
private _restrictProviderAccessFlagEnabled: boolean;
|
||||
protected get restrictProviderAccessEnabled(): boolean {
|
||||
return this._restrictProviderAccessFlagEnabled && this.flexibleCollectionsV1Enabled;
|
||||
return this._restrictProviderAccessFlagEnabled;
|
||||
}
|
||||
|
||||
protected get hideVaultFilters(): boolean {
|
||||
@ -228,10 +218,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
: "trashCleanupWarning",
|
||||
);
|
||||
|
||||
this._flexibleCollectionsV1FlagEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
|
||||
this._restrictProviderAccessFlagEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -254,7 +240,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
switchMap(async ([organization]) => {
|
||||
this.organization = organization;
|
||||
|
||||
if (!organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled)) {
|
||||
if (!organization.canEditAnyCollection) {
|
||||
await this.syncService.fullSync(false);
|
||||
}
|
||||
|
||||
@ -327,12 +313,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
||||
map((collections) => {
|
||||
// Users that can edit all ciphers can implicitly add to / edit within any collection
|
||||
if (
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
)
|
||||
) {
|
||||
if (this.organization.canEditAllCiphers(this.restrictProviderAccessEnabled)) {
|
||||
return collections;
|
||||
}
|
||||
// The user is only allowed to add/edit items to assigned collections that are not readonly
|
||||
@ -377,35 +358,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
// Flexible collections V1 logic.
|
||||
// If the user can edit all ciphers for the organization then fetch them ALL.
|
||||
if (
|
||||
organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
)
|
||||
) {
|
||||
if (organization.canEditAllCiphers(this.restrictProviderAccessEnabled)) {
|
||||
ciphers = await this.cipherService.getAllFromApiForOrganization(organization.id);
|
||||
} else {
|
||||
// Otherwise, only fetch ciphers they have access to (includes unassigned for admins).
|
||||
ciphers = await this.cipherService.getManyFromApiForOrganization(organization.id);
|
||||
}
|
||||
} else {
|
||||
// Pre-flexible collections logic, to be removed after flexible collections is fully released
|
||||
if (
|
||||
organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
)
|
||||
) {
|
||||
ciphers = await this.cipherService.getAllFromApiForOrganization(organization.id);
|
||||
} else {
|
||||
ciphers = (await this.cipherService.getAllDecrypted()).filter(
|
||||
(c) => c.organizationId === organization.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.searchService.indexCiphers(ciphers, organization.id);
|
||||
return ciphers;
|
||||
@ -469,9 +428,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Add access toggle is only shown if allowAdminAccessToAllCollectionItems is false and there are unmanaged collections the user can edit
|
||||
this.showAddAccessToggle =
|
||||
this.flexibleCollectionsV1Enabled &&
|
||||
!this.organization.allowAdminAccessToAllCollectionItems &&
|
||||
this.organization.canEditUnmanagedCollections() &&
|
||||
this.organization.canEditUnmanagedCollections &&
|
||||
collectionsToReturn.some((c) => c.unmanaged);
|
||||
|
||||
if (addAccessStatus === 1 && this.showAddAccessToggle) {
|
||||
@ -508,10 +466,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return (
|
||||
(filter.collectionId === Unassigned &&
|
||||
!organization.canEditUnassignedCiphers(this.restrictProviderAccessEnabled)) ||
|
||||
(!organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
) &&
|
||||
(!organization.canEditAllCiphers(this.restrictProviderAccessEnabled) &&
|
||||
collection != undefined &&
|
||||
!collection.node.assigned)
|
||||
);
|
||||
@ -531,7 +486,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled && showCollectionAccessRestricted) {
|
||||
if (showCollectionAccessRestricted) {
|
||||
// Do not show ciphers for restricted collections
|
||||
// Ciphers belonging to multiple collections may still be present in $allCiphers and shouldn't be visible
|
||||
return [];
|
||||
@ -548,25 +503,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const showMissingCollectionPermissionMessage$ = combineLatest([
|
||||
filter$,
|
||||
selectedCollection$,
|
||||
organization$,
|
||||
]).pipe(
|
||||
map(([filter, collection, organization]) => {
|
||||
return (
|
||||
// Filtering by unassigned, show message if not admin
|
||||
(filter.collectionId === Unassigned &&
|
||||
!organization.canEditUnassignedCiphers(this.restrictProviderAccessEnabled)) ||
|
||||
// Filtering by a collection, so show message if user is not assigned
|
||||
(collection != undefined &&
|
||||
!collection.node.assigned &&
|
||||
!organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled))
|
||||
);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
firstSetup$
|
||||
.pipe(
|
||||
switchMap(() => combineLatest([this.route.queryParams, organization$])),
|
||||
@ -576,17 +512,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
let canEditCipher: boolean;
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
canEditCipher =
|
||||
organization.canEditAllCiphers(true, this.restrictProviderAccessEnabled) ||
|
||||
const canEditCipher =
|
||||
organization.canEditAllCiphers(this.restrictProviderAccessEnabled) ||
|
||||
(await firstValueFrom(allCipherMap$))[cipherId] != undefined;
|
||||
} else {
|
||||
canEditCipher =
|
||||
organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled) ||
|
||||
(await this.cipherService.get(cipherId)) != null;
|
||||
}
|
||||
|
||||
if (canEditCipher) {
|
||||
await this.editCipherId(cipherId);
|
||||
@ -646,7 +574,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
ciphers$,
|
||||
collections$,
|
||||
selectedCollection$,
|
||||
showMissingCollectionPermissionMessage$,
|
||||
showCollectionAccessRestricted$,
|
||||
]),
|
||||
),
|
||||
@ -661,7 +588,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
ciphers,
|
||||
collections,
|
||||
selectedCollection,
|
||||
showMissingCollectionPermissionMessage,
|
||||
showCollectionAccessRestricted,
|
||||
]) => {
|
||||
this.organization = organization;
|
||||
@ -671,7 +597,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.ciphers = ciphers;
|
||||
this.collections = collections;
|
||||
this.selectedCollection = selectedCollection;
|
||||
this.showMissingCollectionPermissionMessage = showMissingCollectionPermissionMessage;
|
||||
this.showCollectionAccessRestricted = showCollectionAccessRestricted;
|
||||
|
||||
this.isEmpty = collections?.length === 0 && ciphers?.length === 0;
|
||||
@ -812,20 +737,19 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async editCipherCollections(cipher: CipherView) {
|
||||
let collections: CollectionAdminView[] = [];
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
// V1 limits admins to only adding items to collections they have access to.
|
||||
// Admins limited to only adding items to collections they have access to.
|
||||
collections = await firstValueFrom(
|
||||
this.allCollectionsWithoutUnassigned$.pipe(
|
||||
map((c) => {
|
||||
return c.sort((a, b) => {
|
||||
if (
|
||||
a.canEditItems(this.organization, true, this.restrictProviderAccessEnabled) &&
|
||||
!b.canEditItems(this.organization, true, this.restrictProviderAccessEnabled)
|
||||
a.canEditItems(this.organization, this.restrictProviderAccessEnabled) &&
|
||||
!b.canEditItems(this.organization, this.restrictProviderAccessEnabled)
|
||||
) {
|
||||
return -1;
|
||||
} else if (
|
||||
!a.canEditItems(this.organization, true, this.restrictProviderAccessEnabled) &&
|
||||
b.canEditItems(this.organization, true, this.restrictProviderAccessEnabled)
|
||||
!a.canEditItems(this.organization, this.restrictProviderAccessEnabled) &&
|
||||
b.canEditItems(this.organization, this.restrictProviderAccessEnabled)
|
||||
) {
|
||||
return 1;
|
||||
} else {
|
||||
@ -835,9 +759,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
collections = await firstValueFrom(this.allCollectionsWithoutUnassigned$);
|
||||
}
|
||||
const dialog = openOrgVaultCollectionsDialog(this.dialogService, {
|
||||
data: {
|
||||
collectionIds: cipher.collectionIds,
|
||||
@ -855,14 +776,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async addCipher() {
|
||||
let collections: CollectionView[] = [];
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
// V1 limits admins to only adding items to collections they have access to.
|
||||
// Admins limited to only adding items to collections they have access to.
|
||||
collections = await firstValueFrom(this.editableCollections$);
|
||||
} else {
|
||||
collections = (await firstValueFrom(this.vaultFilterService.filteredCollections$)).filter(
|
||||
(c) => !c.readOnly && c.id != Unassigned,
|
||||
);
|
||||
}
|
||||
|
||||
await this.editCipher(null, (comp) => {
|
||||
comp.type = this.activeFilter.cipherType;
|
||||
@ -954,14 +869,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
let collections: CollectionView[] = [];
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
// V1 limits admins to only adding items to collections they have access to.
|
||||
// Admins limited to only adding items to collections they have access to.
|
||||
collections = await firstValueFrom(this.editableCollections$);
|
||||
} else {
|
||||
collections = (await firstValueFrom(this.vaultFilterService.filteredCollections$)).filter(
|
||||
(c) => !c.readOnly && c.id != Unassigned,
|
||||
);
|
||||
}
|
||||
|
||||
await this.editCipher(cipher, (comp) => {
|
||||
comp.cloneMode = true;
|
||||
@ -977,7 +886,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (
|
||||
!this.organization.permissions.editAnyCollection &&
|
||||
this.flexibleCollectionsV1Enabled &&
|
||||
!c.edit &&
|
||||
!this.organization.allowAdminAccessToAllCollectionItems
|
||||
) {
|
||||
@ -991,9 +899,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Allow restore of an Unassigned Item
|
||||
try {
|
||||
const asAdmin =
|
||||
this.organization?.canEditAnyCollection(this.flexibleCollectionsV1Enabled) ||
|
||||
c.isUnassigned;
|
||||
const asAdmin = this.organization?.canEditAnyCollection || c.isUnassigned;
|
||||
await this.cipherService.restoreWithServer(c.id, asAdmin);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
@ -1009,7 +915,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async bulkRestore(ciphers: CipherView[]) {
|
||||
if (
|
||||
!this.organization.permissions.editAnyCollection &&
|
||||
this.flexibleCollectionsV1Enabled &&
|
||||
ciphers.some((c) => !c.edit && !this.organization.allowAdminAccessToAllCollectionItems)
|
||||
) {
|
||||
this.showMissingPermissionsError();
|
||||
@ -1025,10 +930,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
const unassignedCiphers: string[] = [];
|
||||
|
||||
// If user has edit all Access no need to check for unassigned ciphers
|
||||
const canEditAll = this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
);
|
||||
const canEditAll = this.organization.canEditAllCiphers(this.restrictProviderAccessEnabled);
|
||||
|
||||
if (canEditAll) {
|
||||
ciphers.map((cipher) => {
|
||||
@ -1069,14 +971,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async deleteCipher(c: CipherView): Promise<boolean> {
|
||||
if (
|
||||
this.flexibleCollectionsV1Enabled &&
|
||||
!c.edit &&
|
||||
!this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
)
|
||||
) {
|
||||
if (!c.edit && !this.organization.canEditAllCiphers(this.restrictProviderAccessEnabled)) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -1111,7 +1006,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async deleteCollection(collection: CollectionAdminView): Promise<void> {
|
||||
if (!collection.canDelete(this.organization, this.flexibleCollectionsV1Enabled)) {
|
||||
if (!collection.canDelete(this.organization)) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -1178,17 +1073,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
const canDeleteCollections =
|
||||
collections == null ||
|
||||
collections.every((c) => c.canDelete(organization, this.flexibleCollectionsV1Enabled));
|
||||
collections == null || collections.every((c) => c.canDelete(organization));
|
||||
const canDeleteCiphers =
|
||||
ciphers == null ||
|
||||
ciphers.every((c) => c.edit) ||
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
);
|
||||
this.organization.canEditAllCiphers(this.restrictProviderAccessEnabled);
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled && (!canDeleteCiphers || !canDeleteCollections)) {
|
||||
if (!canDeleteCiphers || !canDeleteCollections) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -1268,9 +1159,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
data: {
|
||||
organizationId: this.organization?.id,
|
||||
parentCollectionId: this.selectedCollection?.node.id,
|
||||
limitNestedCollections: !this.organization.canEditAnyCollection(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
),
|
||||
limitNestedCollections: !this.organization.canEditAnyCollection,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1295,9 +1184,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
initialTab: tab,
|
||||
readonly: readonly,
|
||||
isAddAccessCollection: c.unmanaged,
|
||||
limitNestedCollections: !this.organization.canEditAnyCollection(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
),
|
||||
limitNestedCollections: !this.organization.canEditAnyCollection,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1335,10 +1222,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.flexibleCollectionsV1Enabled &&
|
||||
collections.some((c) => !c.canEdit(organization, this.flexibleCollectionsV1Enabled))
|
||||
) {
|
||||
if (collections.some((c) => !c.canEdit(organization))) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
@ -1366,15 +1250,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
let availableCollections: CollectionView[];
|
||||
|
||||
if (this.flexibleCollectionsV1Enabled) {
|
||||
availableCollections = await firstValueFrom(this.editableCollections$);
|
||||
} else {
|
||||
availableCollections = (
|
||||
await firstValueFrom(this.vaultFilterService.filteredCollections$)
|
||||
).filter((c) => c.id != Unassigned);
|
||||
}
|
||||
const availableCollections = await firstValueFrom(this.editableCollections$);
|
||||
|
||||
const dialog = AssignCollectionsWebComponent.open(this.dialogService, {
|
||||
data: {
|
||||
@ -1405,10 +1281,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected deleteCipherWithServer(id: string, permanent: boolean, isUnassigned: boolean) {
|
||||
const asAdmin =
|
||||
this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccessEnabled,
|
||||
) || isUnassigned;
|
||||
this.organization?.canEditAllCiphers(this.restrictProviderAccessEnabled) || isUnassigned;
|
||||
return permanent
|
||||
? this.cipherService.deleteWithServer(id, asAdmin)
|
||||
: this.cipherService.softDeleteWithServer(id, asAdmin);
|
||||
|
@ -24,7 +24,6 @@ export class CollectionsComponent implements OnInit {
|
||||
collectionIds: string[];
|
||||
collections: CollectionView[] = [];
|
||||
organization: Organization;
|
||||
flexibleCollectionsV1Enabled: boolean;
|
||||
restrictProviderAccess: boolean;
|
||||
|
||||
protected cipherDomain: Cipher;
|
||||
@ -40,9 +39,6 @@ export class CollectionsComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
this.restrictProviderAccess = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -72,12 +68,7 @@ export class CollectionsComponent implements OnInit {
|
||||
async submit(): Promise<boolean> {
|
||||
const selectedCollectionIds = this.collections
|
||||
.filter((c) => {
|
||||
if (
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return !!(c as any).checked;
|
||||
} else {
|
||||
return !!(c as any).checked && c.readOnly == null;
|
||||
|
@ -90,7 +90,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
private personalOwnershipPolicyAppliesToActiveUser: boolean;
|
||||
private previousCipherId: string;
|
||||
|
||||
protected flexibleCollectionsV1Enabled = false;
|
||||
protected restrictProviderAccess = false;
|
||||
|
||||
get fido2CredentialCreationDateValue(): string {
|
||||
@ -181,9 +180,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
this.restrictProviderAccess = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -674,10 +670,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected saveCipher(cipher: Cipher) {
|
||||
const isNotClone = this.editMode && !this.cloneMode;
|
||||
let orgAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
let orgAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
|
||||
// if a cipher is unassigned we want to check if they are an admin or have permission to edit any collection
|
||||
if (!cipher.collectionIds) {
|
||||
@ -690,20 +683,14 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
protected deleteCipher() {
|
||||
const asAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
return this.cipher.isDeleted
|
||||
? this.cipherService.deleteWithServer(this.cipher.id, asAdmin)
|
||||
: this.cipherService.softDeleteWithServer(this.cipher.id, asAdmin);
|
||||
}
|
||||
|
||||
protected restoreCipher() {
|
||||
const asAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
return this.cipherService.restoreWithServer(this.cipher.id, asAdmin);
|
||||
}
|
||||
|
||||
|
@ -168,13 +168,8 @@ export class Organization {
|
||||
);
|
||||
}
|
||||
|
||||
canEditAnyCollection(flexibleCollectionsV1Enabled: boolean) {
|
||||
if (!flexibleCollectionsV1Enabled) {
|
||||
// Pre-Flexible Collections v1 logic
|
||||
return this.isAdmin || this.permissions.editAnyCollection;
|
||||
}
|
||||
|
||||
// Post Flexible Collections V1, the allowAdminAccessToAllCollectionItems flag can restrict admins
|
||||
get canEditAnyCollection() {
|
||||
// The allowAdminAccessToAllCollectionItems flag can restrict admins
|
||||
// Providers and custom users with canEditAnyCollection are not affected by allowAdminAccessToAllCollectionItems flag
|
||||
return (
|
||||
this.isProviderUser ||
|
||||
@ -183,7 +178,7 @@ export class Organization {
|
||||
);
|
||||
}
|
||||
|
||||
canEditUnmanagedCollections() {
|
||||
get canEditUnmanagedCollections() {
|
||||
// Any admin or custom user with editAnyCollection permission can edit unmanaged collections
|
||||
return this.isAdmin || this.permissions.editAnyCollection;
|
||||
}
|
||||
@ -203,15 +198,7 @@ export class Organization {
|
||||
);
|
||||
}
|
||||
|
||||
canEditAllCiphers(
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
restrictProviderAccessFlagEnabled: boolean,
|
||||
) {
|
||||
// Before Flexible Collections V1, any admin or anyone with editAnyCollection permission could edit all ciphers
|
||||
if (!flexibleCollectionsV1Enabled) {
|
||||
return this.isAdmin || this.permissions.editAnyCollection;
|
||||
}
|
||||
|
||||
canEditAllCiphers(restrictProviderAccessFlagEnabled: boolean) {
|
||||
// Providers can access items until the restrictProviderAccess flag is enabled
|
||||
// After the flag is enabled and removed, this block will be deleted
|
||||
// so that they permanently lose access to items
|
||||
@ -219,7 +206,7 @@ export class Organization {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Post Flexible Collections V1, the allowAdminAccessToAllCollectionItems flag can restrict admins
|
||||
// The allowAdminAccessToAllCollectionItems flag can restrict admins
|
||||
// Custom users with canEditAnyCollection are not affected by allowAdminAccessToAllCollectionItems flag
|
||||
return (
|
||||
(this.type === OrganizationUserType.Custom && this.permissions.editAnyCollection) ||
|
||||
@ -229,10 +216,9 @@ export class Organization {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flexibleCollectionsV1Enabled - Whether or not the V1 Flexible Collection feature flag is enabled
|
||||
* @returns True if the user can delete any collection
|
||||
*/
|
||||
canDeleteAnyCollection(flexibleCollectionsV1Enabled: boolean) {
|
||||
get canDeleteAnyCollection() {
|
||||
// Providers and Users with DeleteAnyCollection permission can always delete collections
|
||||
if (this.isProviderUser || this.permissions.deleteAnyCollection) {
|
||||
return true;
|
||||
@ -240,7 +226,7 @@ export class Organization {
|
||||
|
||||
// If AllowAdminAccessToAllCollectionItems is true, Owners and Admins can delete any collection, regardless of LimitCollectionCreationDeletion setting
|
||||
// Using explicit type checks because provider users are handled above and this mimics the server's permission checks closely
|
||||
if (!flexibleCollectionsV1Enabled || this.allowAdminAccessToAllCollectionItems) {
|
||||
if (this.allowAdminAccessToAllCollectionItems) {
|
||||
return this.type == OrganizationUserType.Owner || this.type == OrganizationUserType.Admin;
|
||||
}
|
||||
|
||||
|
@ -38,11 +38,7 @@ export class CollectionView implements View, ITreeNodeObject {
|
||||
}
|
||||
}
|
||||
|
||||
canEditItems(
|
||||
org: Organization,
|
||||
v1FlexibleCollections: boolean,
|
||||
restrictProviderAccess: boolean,
|
||||
): boolean {
|
||||
canEditItems(org: Organization, restrictProviderAccess: boolean): boolean {
|
||||
if (org != null && org.id !== this.organizationId) {
|
||||
throw new Error(
|
||||
"Id of the organization provided does not match the org id of the collection.",
|
||||
@ -50,7 +46,7 @@ export class CollectionView implements View, ITreeNodeObject {
|
||||
}
|
||||
|
||||
return (
|
||||
org?.canEditAllCiphers(v1FlexibleCollections, restrictProviderAccess) ||
|
||||
org?.canEditAllCiphers(restrictProviderAccess) ||
|
||||
this.manage ||
|
||||
(this.assigned && !this.readOnly)
|
||||
);
|
||||
@ -58,28 +54,23 @@ export class CollectionView implements View, ITreeNodeObject {
|
||||
|
||||
/**
|
||||
* Returns true if the user can edit a collection (including user and group access) from the individual vault.
|
||||
* After FCv1, does not include admin permissions - see {@link CollectionAdminView.canEdit}.
|
||||
* Does not include admin permissions - see {@link CollectionAdminView.canEdit}.
|
||||
*/
|
||||
canEdit(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
canEdit(org: Organization): boolean {
|
||||
if (org != null && org.id !== this.organizationId) {
|
||||
throw new Error(
|
||||
"Id of the organization provided does not match the org id of the collection.",
|
||||
);
|
||||
}
|
||||
|
||||
if (flexibleCollectionsV1Enabled) {
|
||||
// Only use individual permissions, not admin permissions
|
||||
return this.manage;
|
||||
}
|
||||
|
||||
return org?.canEditAnyCollection(flexibleCollectionsV1Enabled) || this.manage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user can delete a collection from the individual vault.
|
||||
* After FCv1, does not include admin permissions - see {@link CollectionAdminView.canDelete}.
|
||||
* Does not include admin permissions - see {@link CollectionAdminView.canDelete}.
|
||||
*/
|
||||
canDelete(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean {
|
||||
canDelete(org: Organization): boolean {
|
||||
if (org != null && org.id !== this.organizationId) {
|
||||
throw new Error(
|
||||
"Id of the organization provided does not match the org id of the collection.",
|
||||
@ -88,24 +79,14 @@ export class CollectionView implements View, ITreeNodeObject {
|
||||
|
||||
const canDeleteManagedCollections = !org?.limitCollectionCreationDeletion || org.isAdmin;
|
||||
|
||||
if (flexibleCollectionsV1Enabled) {
|
||||
// Only use individual permissions, not admin permissions
|
||||
return canDeleteManagedCollections && this.manage;
|
||||
}
|
||||
|
||||
return (
|
||||
org?.canDeleteAnyCollection(flexibleCollectionsV1Enabled) ||
|
||||
(canDeleteManagedCollections && this.manage)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user can view collection info and access in a read-only state from the individual vault
|
||||
*/
|
||||
canViewCollectionInfo(
|
||||
org: Organization | undefined,
|
||||
flexibleCollectionsV1Enabled: boolean,
|
||||
): boolean {
|
||||
canViewCollectionInfo(org: Organization | undefined): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,6 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
const v1FCEnabled = await this.configService.getFeatureFlag(FeatureFlag.FlexibleCollectionsV1);
|
||||
const restrictProviderAccess = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@ -186,7 +185,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
|
||||
this.showOrgSelector = true;
|
||||
}
|
||||
|
||||
await this.initializeItems(this.selectedOrgId, v1FCEnabled, restrictProviderAccess);
|
||||
await this.initializeItems(this.selectedOrgId, restrictProviderAccess);
|
||||
|
||||
if (this.selectedOrgId && this.selectedOrgId !== MY_VAULT_ID) {
|
||||
await this.handleOrganizationCiphers();
|
||||
@ -332,11 +331,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
|
||||
}
|
||||
}
|
||||
|
||||
private async initializeItems(
|
||||
organizationId: OrganizationId,
|
||||
v1FCEnabled: boolean,
|
||||
restrictProviderAccess: boolean,
|
||||
) {
|
||||
private async initializeItems(organizationId: OrganizationId, restrictProviderAccess: boolean) {
|
||||
this.totalItemCount = this.params.ciphers.length;
|
||||
|
||||
// If organizationId is not present or organizationId is MyVault, then all ciphers are considered personal items
|
||||
@ -351,7 +346,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
|
||||
const org = await this.organizationService.get(organizationId);
|
||||
this.orgName = org.name;
|
||||
|
||||
this.editableItems = org.canEditAllCiphers(v1FCEnabled, restrictProviderAccess)
|
||||
this.editableItems = org.canEditAllCiphers(restrictProviderAccess)
|
||||
? this.params.ciphers
|
||||
: this.params.ciphers.filter((c) => c.edit);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user