mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +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 {
|
export class SelectionReadOnly {
|
||||||
static template(): 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;
|
id: string;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
hidePasswords: 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.id = id;
|
||||||
this.readOnly = readOnly;
|
this.readOnly = readOnly;
|
||||||
this.hidePasswords = hidePasswords || false;
|
this.hidePasswords = hidePasswords || false;
|
||||||
|
this.manage = manage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,9 @@ export class EditCommand {
|
|||||||
const groups =
|
const groups =
|
||||||
req.groups == null
|
req.groups == null
|
||||||
? 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();
|
const request = new CollectionRequest();
|
||||||
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
||||||
request.externalId = req.externalId;
|
request.externalId = req.externalId;
|
||||||
|
|||||||
@@ -425,7 +425,9 @@ export class GetCommand extends DownloadCommand {
|
|||||||
const groups =
|
const groups =
|
||||||
response.groups == null
|
response.groups == null
|
||||||
? 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);
|
const res = new OrganizationCollectionResponse(decCollection, groups);
|
||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -180,7 +180,9 @@ export class CreateCommand {
|
|||||||
const groups =
|
const groups =
|
||||||
req.groups == null
|
req.groups == null
|
||||||
? 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();
|
const request = new CollectionRequest();
|
||||||
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
||||||
request.externalId = req.externalId;
|
request.externalId = req.externalId;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class InternalGroupService extends GroupService {
|
|||||||
request.accessAll = group.accessAll;
|
request.accessAll = group.accessAll;
|
||||||
request.users = group.members;
|
request.users = group.members;
|
||||||
request.collections = group.collections.map(
|
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) {
|
if (group.id == undefined) {
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export class UserAdminService {
|
|||||||
id: c.id,
|
id: c.id,
|
||||||
hidePasswords: c.hidePasswords,
|
hidePasswords: c.hidePasswords,
|
||||||
readOnly: c.readOnly,
|
readOnly: c.readOnly,
|
||||||
|
manage: c.manage,
|
||||||
}));
|
}));
|
||||||
view.groups = u.groups;
|
view.groups = u.groups;
|
||||||
view.accessSecretsManager = u.accessSecretsManager;
|
view.accessSecretsManager = u.accessSecretsManager;
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ interface SelectionResponseLike {
|
|||||||
id: string;
|
id: string;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
hidePasswords: boolean;
|
hidePasswords: boolean;
|
||||||
|
manage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CollectionAccessSelectionView extends View {
|
export class CollectionAccessSelectionView extends View {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly readOnly: boolean;
|
readonly readOnly: boolean;
|
||||||
readonly hidePasswords: boolean;
|
readonly hidePasswords: boolean;
|
||||||
|
readonly manage: boolean;
|
||||||
|
|
||||||
constructor(response?: SelectionResponseLike) {
|
constructor(response?: SelectionResponseLike) {
|
||||||
super();
|
super();
|
||||||
@@ -21,5 +23,6 @@ export class CollectionAccessSelectionView extends View {
|
|||||||
this.id = response.id;
|
this.id = response.id;
|
||||||
this.readOnly = response.readOnly;
|
this.readOnly = response.readOnly;
|
||||||
this.hidePasswords = response.hidePasswords;
|
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)
|
.filter((u) => (u as any).checked && !u.accessAll)
|
||||||
.map(
|
.map(
|
||||||
(u) =>
|
(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.formPromise = this.apiService.putCollectionUsers(
|
||||||
this.organizationId,
|
this.organizationId,
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
|
|||||||
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
|
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
|
||||||
{ perm: CollectionPermission.Edit, labelId: "canEdit" },
|
{ perm: CollectionPermission.Edit, labelId: "canEdit" },
|
||||||
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
|
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
|
||||||
|
{ perm: CollectionPermission.Manage, labelId: "canManage" },
|
||||||
];
|
];
|
||||||
protected initialPermission = CollectionPermission.View;
|
protected initialPermission = CollectionPermission.View;
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import { SelectItemView } from "@bitwarden/components";
|
|||||||
import { CollectionAccessSelectionView } from "../../../core";
|
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 {
|
export enum CollectionPermission {
|
||||||
View = "view",
|
View = "view",
|
||||||
ViewExceptPass = "viewExceptPass",
|
ViewExceptPass = "viewExceptPass",
|
||||||
Edit = "edit",
|
Edit = "edit",
|
||||||
EditExceptPass = "editExceptPass",
|
EditExceptPass = "editExceptPass",
|
||||||
|
Manage = "manage",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccessItemType {
|
export enum AccessItemType {
|
||||||
@@ -82,7 +83,9 @@ export type AccessItemValue = {
|
|||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
export const convertToPermission = (value: CollectionAccessSelectionView) => {
|
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;
|
return value.hidePasswords ? CollectionPermission.ViewExceptPass : CollectionPermission.View;
|
||||||
} else {
|
} else {
|
||||||
return value.hidePasswords ? CollectionPermission.EditExceptPass : CollectionPermission.Edit;
|
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
|
* 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
|
* @param value
|
||||||
*/
|
*/
|
||||||
export const convertToSelectionView = (value: AccessItemValue) => {
|
export const convertToSelectionView = (value: AccessItemValue) => {
|
||||||
@@ -99,6 +102,7 @@ export const convertToSelectionView = (value: AccessItemValue) => {
|
|||||||
id: value.id,
|
id: value.id,
|
||||||
readOnly: readOnly(value.permission),
|
readOnly: readOnly(value.permission),
|
||||||
hidePasswords: hidePassword(value.permission),
|
hidePasswords: hidePassword(value.permission),
|
||||||
|
manage: value.permission === CollectionPermission.Manage,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,7 @@ function createCollectionView(i: number): CollectionAdminView {
|
|||||||
id: group.id,
|
id: group.id,
|
||||||
hidePasswords: false,
|
hidePasswords: false,
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
|
manage: false,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,10 +105,12 @@ export class CollectionAdminService {
|
|||||||
collection.externalId = model.externalId;
|
collection.externalId = model.externalId;
|
||||||
collection.name = (await this.cryptoService.encrypt(model.name, key)).encryptedString;
|
collection.name = (await this.cryptoService.encrypt(model.name, key)).encryptedString;
|
||||||
collection.groups = model.groups.map(
|
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(
|
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;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1479,6 +1479,9 @@
|
|||||||
"manage": {
|
"manage": {
|
||||||
"message": "Manage"
|
"message": "Manage"
|
||||||
},
|
},
|
||||||
|
"canManage": {
|
||||||
|
"message": "Can manage"
|
||||||
|
},
|
||||||
"disable": {
|
"disable": {
|
||||||
"message": "Turn off"
|
"message": "Turn off"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ export class SelectionReadOnlyRequest {
|
|||||||
id: string;
|
id: string;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
hidePasswords: 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.id = id;
|
||||||
this.readOnly = readOnly;
|
this.readOnly = readOnly;
|
||||||
this.hidePasswords = hidePasswords;
|
this.hidePasswords = hidePasswords;
|
||||||
|
this.manage = manage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ export class SelectionReadOnlyResponse extends BaseResponse {
|
|||||||
id: string;
|
id: string;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
hidePasswords: boolean;
|
hidePasswords: boolean;
|
||||||
|
manage: boolean;
|
||||||
|
|
||||||
constructor(response: any) {
|
constructor(response: any) {
|
||||||
super(response);
|
super(response);
|
||||||
this.id = this.getResponseProperty("Id");
|
this.id = this.getResponseProperty("Id");
|
||||||
this.readOnly = this.getResponseProperty("ReadOnly");
|
this.readOnly = this.getResponseProperty("ReadOnly");
|
||||||
this.hidePasswords = this.getResponseProperty("HidePasswords");
|
this.hidePasswords = this.getResponseProperty("HidePasswords");
|
||||||
|
this.manage = this.getResponseProperty("Manage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user