1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00

[AC-1117] Add manage permission (#5910)

* Add 'manage' option to collection access permissions

* Add 'manage' to collection permissions

* remove service accidentally committed from another branch

* Update CLI commands

* update message casing to be consistent

* access selector model updates
This commit is contained in:
Robyn MacCallum
2023-08-11 14:51:46 -04:00
committed by GitHub
parent a05b4fd094
commit c3bcd732cf
15 changed files with 45 additions and 13 deletions

View File

@@ -1,15 +1,17 @@
export class SelectionReadOnly {
static template(): SelectionReadOnly {
return new SelectionReadOnly("00000000-0000-0000-0000-000000000000", false, false);
return new SelectionReadOnly("00000000-0000-0000-0000-000000000000", false, false, false);
}
id: string;
readOnly: boolean;
hidePasswords: boolean;
manage: boolean;
constructor(id: string, readOnly: boolean, hidePasswords: boolean) {
constructor(id: string, readOnly: boolean, hidePasswords: boolean, manage: boolean) {
this.id = id;
this.readOnly = readOnly;
this.hidePasswords = hidePasswords || false;
this.manage = manage;
}
}

View File

@@ -163,7 +163,9 @@ export class EditCommand {
const groups =
req.groups == null
? null
: req.groups.map((g) => new SelectionReadOnlyRequest(g.id, g.readOnly, g.hidePasswords));
: req.groups.map(
(g) => new SelectionReadOnlyRequest(g.id, g.readOnly, g.hidePasswords, g.manage)
);
const request = new CollectionRequest();
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
request.externalId = req.externalId;

View File

@@ -425,7 +425,9 @@ export class GetCommand extends DownloadCommand {
const groups =
response.groups == null
? null
: response.groups.map((g) => new SelectionReadOnly(g.id, g.readOnly, g.hidePasswords));
: response.groups.map(
(g) => new SelectionReadOnly(g.id, g.readOnly, g.hidePasswords, g.manage)
);
const res = new OrganizationCollectionResponse(decCollection, groups);
return Response.success(res);
} catch (e) {

View File

@@ -180,7 +180,9 @@ export class CreateCommand {
const groups =
req.groups == null
? null
: req.groups.map((g) => new SelectionReadOnlyRequest(g.id, g.readOnly, g.hidePasswords));
: req.groups.map(
(g) => new SelectionReadOnlyRequest(g.id, g.readOnly, g.hidePasswords, g.manage)
);
const request = new CollectionRequest();
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
request.externalId = req.externalId;

View File

@@ -76,7 +76,7 @@ export class InternalGroupService extends GroupService {
request.accessAll = group.accessAll;
request.users = group.members;
request.collections = group.collections.map(
(c) => new SelectionReadOnlyRequest(c.id, c.readOnly, c.hidePasswords)
(c) => new SelectionReadOnlyRequest(c.id, c.readOnly, c.hidePasswords, c.manage)
);
if (group.id == undefined) {

View File

@@ -80,6 +80,7 @@ export class UserAdminService {
id: c.id,
hidePasswords: c.hidePasswords,
readOnly: c.readOnly,
manage: c.manage,
}));
view.groups = u.groups;
view.accessSecretsManager = u.accessSecretsManager;

View File

@@ -4,12 +4,14 @@ interface SelectionResponseLike {
id: string;
readOnly: boolean;
hidePasswords: boolean;
manage: boolean;
}
export class CollectionAccessSelectionView extends View {
readonly id: string;
readonly readOnly: boolean;
readonly hidePasswords: boolean;
readonly manage: boolean;
constructor(response?: SelectionResponseLike) {
super();
@@ -21,5 +23,6 @@ export class CollectionAccessSelectionView extends View {
this.id = response.id;
this.readOnly = response.readOnly;
this.hidePasswords = response.hidePasswords;
this.manage = response.manage;
}
}

View File

@@ -142,7 +142,12 @@ export class EntityUsersComponent implements OnInit {
.filter((u) => (u as any).checked && !u.accessAll)
.map(
(u) =>
new SelectionReadOnlyRequest(u.id, !!(u as any).readOnly, !!(u as any).hidePasswords)
new SelectionReadOnlyRequest(
u.id,
!!(u as any).readOnly,
!!(u as any).hidePasswords,
!!(u as any).manage
)
);
this.formPromise = this.apiService.putCollectionUsers(
this.organizationId,

View File

@@ -121,6 +121,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
{ perm: CollectionPermission.Edit, labelId: "canEdit" },
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
{ perm: CollectionPermission.Manage, labelId: "canManage" },
];
protected initialPermission = CollectionPermission.View;

View File

@@ -7,13 +7,14 @@ import { SelectItemView } from "@bitwarden/components";
import { CollectionAccessSelectionView } from "../../../core";
/**
* Permission options that replace/correspond with readOnly and hidePassword server fields.
* Permission options that replace/correspond with manage, readOnly, and hidePassword server fields.
*/
export enum CollectionPermission {
View = "view",
ViewExceptPass = "viewExceptPass",
Edit = "edit",
EditExceptPass = "editExceptPass",
Manage = "manage",
}
export enum AccessItemType {
@@ -82,7 +83,9 @@ export type AccessItemValue = {
* @param value
*/
export const convertToPermission = (value: CollectionAccessSelectionView) => {
if (value.readOnly) {
if (value.manage) {
return CollectionPermission.Manage;
} else if (value.readOnly) {
return value.hidePasswords ? CollectionPermission.ViewExceptPass : CollectionPermission.View;
} else {
return value.hidePasswords ? CollectionPermission.EditExceptPass : CollectionPermission.Edit;
@@ -91,7 +94,7 @@ export const convertToPermission = (value: CollectionAccessSelectionView) => {
/**
* Converts an AccessItemValue back into a CollectionAccessView class using the CollectionPermission
* to determine the values for `readOnly` and `hidePassword`
* to determine the values for `manage`, `readOnly`, and `hidePassword`
* @param value
*/
export const convertToSelectionView = (value: AccessItemValue) => {
@@ -99,6 +102,7 @@ export const convertToSelectionView = (value: AccessItemValue) => {
id: value.id,
readOnly: readOnly(value.permission),
hidePasswords: hidePassword(value.permission),
manage: value.permission === CollectionPermission.Manage,
});
};

View File

@@ -298,6 +298,7 @@ function createCollectionView(i: number): CollectionAdminView {
id: group.id,
hidePasswords: false,
readOnly: false,
manage: false,
}),
];
}

View File

@@ -105,10 +105,12 @@ export class CollectionAdminService {
collection.externalId = model.externalId;
collection.name = (await this.cryptoService.encrypt(model.name, key)).encryptedString;
collection.groups = model.groups.map(
(group) => new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords)
(group) =>
new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords, group.manage)
);
collection.users = model.users.map(
(user) => new SelectionReadOnlyRequest(user.id, user.readOnly, user.hidePasswords)
(user) =>
new SelectionReadOnlyRequest(user.id, user.readOnly, user.hidePasswords, user.manage)
);
return collection;
}

View File

@@ -1479,6 +1479,9 @@
"manage": {
"message": "Manage"
},
"canManage": {
"message": "Can manage"
},
"disable": {
"message": "Turn off"
},

View File

@@ -2,10 +2,12 @@ export class SelectionReadOnlyRequest {
id: string;
readOnly: boolean;
hidePasswords: boolean;
manage: boolean;
constructor(id: string, readOnly: boolean, hidePasswords: boolean) {
constructor(id: string, readOnly: boolean, hidePasswords: boolean, manage: boolean) {
this.id = id;
this.readOnly = readOnly;
this.hidePasswords = hidePasswords;
this.manage = manage;
}
}

View File

@@ -4,11 +4,13 @@ export class SelectionReadOnlyResponse extends BaseResponse {
id: string;
readOnly: boolean;
hidePasswords: boolean;
manage: boolean;
constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.readOnly = this.getResponseProperty("ReadOnly");
this.hidePasswords = this.getResponseProperty("HidePasswords");
this.manage = this.getResponseProperty("Manage");
}
}