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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -298,6 +298,7 @@ function createCollectionView(i: number): CollectionAdminView {
|
||||
id: group.id,
|
||||
hidePasswords: false,
|
||||
readOnly: false,
|
||||
manage: false,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1479,6 +1479,9 @@
|
||||
"manage": {
|
||||
"message": "Manage"
|
||||
},
|
||||
"canManage": {
|
||||
"message": "Can manage"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Turn off"
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user