diff --git a/caosdb-proto b/caosdb-proto index 533c8e7341d0659e3cc43d834793a7a965703f55..c6405e538c179d2a8af952f85d9e9dc51fbadb92 160000 --- a/caosdb-proto +++ b/caosdb-proto @@ -1 +1 @@ -Subproject commit 533c8e7341d0659e3cc43d834793a7a965703f55 +Subproject commit c6405e538c179d2a8af952f85d9e9dc51fbadb92 diff --git a/src/EntityACL.js b/src/EntityACL.js new file mode 100644 index 0000000000000000000000000000000000000000..fc4eb782ffe27e21a4822178e46cdcb554465c22 --- /dev/null +++ b/src/EntityACL.js @@ -0,0 +1,328 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +import { + api +} from "./EntityApi"; + + +export class EntityACI { + constructor({ + role, + grant, + priority, + permissions, + capabilities + }) { + this.role = role; + this.grant = grant; + this.priority = priority; + this.permissions = permissions || { + retrieve_entity: false, + retrieve_acl: false, + retrieve_history: false, + retrieve_owner: false, + retrieve_file: false, + delete_entity: false, + edit_acl: false, + update_description: false, + update_value: false, + update_role: false, + update_remove_parent: false, + update_add_parent: false, + update_remove_property: false, + update_add_property: false, + update_name: false, + update_data_type: false, + update_query_template_definition: false, + update_remove_file: false, + update_add_file: false, + update_move_file: false, + use_as_reference: false, + use_as_property: false, + use_as_parent: false, + use_as_data_type: false, + } + this.capabilities = capabilities || { + delete_aci: false, + } + } + + isEditAcl() { + return this.permissions.edit_acl; + } + + setEditAcl(val) { + val = typeof val === "undefined" ? true : val; + this.permissions.edit_acl = val; + } + + isDelete() { + return this.permissions.delete_entity; + } + + setDelete(val) { + val = typeof val === "undefined" ? true : val; + this.permissions.delete_entity = val; + } + + isFullRetrieve() { + return this.permissions.retrieve_entity && + this.permissions.retrieve_acl && + this.permissions.retrieve_history && + this.permissions.retrieve_owner && + this.permissions.retrieve_file; + } + + setFullRetrieve(val) { + val = typeof val === "undefined" ? true : val; + this.permissions.retrieve_entity = val; + this.permissions.retrieve_acl = val; + this.permissions.retrieve_history = val; + this.permissions.retrieve_owner = val; + this.permissions.retrieve_file = val; + } + + isPartialRetrieve() { + return this.permissions.retrieve_entity || + this.permissions.retrieve_acl || + this.permissions.retrieve_history || + this.permissions.retrieve_owner || + this.permissions.retrieve_file; + } + + isFullUse() { + return this.permissions.use_as_reference && + this.permissions.use_as_property && + this.permissions.use_as_parent && + this.permissions.use_as_data_type; + } + + setFullUse(val) { + val = typeof val === "undefined" ? true : val; + this.permissions.use_as_reference = val; + this.permissions.use_as_property = val; + this.permissions.use_as_parent = val; + this.permissions.use_as_data_type = val; + } + + isPartialUse() { + return this.permissions.use_as_reference || + this.permissions.use_as_property || + this.permissions.use_as_parent || + this.permissions.use_as_data_type; + } + + isFullUpdate() { + return this.permissions.update_description && + this.permissions.update_value && + this.permissions.update_role && + this.permissions.update_remove_parent && + this.permissions.update_add_parent && + this.permissions.update_remove_property && + this.permissions.update_add_property && + this.permissions.update_name && + this.permissions.update_data_type && + this.permissions.update_query_template_definition && + this.permissions.update_remove_file && + this.permissions.update_add_file && + this.permissions.update_move_file; + } + + setFullUpdate(val) { + val = typeof val === "undefined" ? true : val; + this.permissions.update_description = val; + this.permissions.update_value = val; + this.permissions.update_role = val; + this.permissions.update_remove_parent = val; + this.permissions.update_add_parent = val; + this.permissions.update_remove_property = val; + this.permissions.update_add_property = val; + this.permissions.update_name = val; + this.permissions.update_data_type = val; + this.permissions.update_query_template_definition = val; + this.permissions.update_remove_file = val; + this.permissions.update_add_file = val; + this.permissions.update_move_file = val; + } + + isPartialUpdate() { + return this.permissions.update_description || + this.permissions.update_value || + this.permissions.update_role || + this.permissions.update_remove_parent || + this.permissions.update_add_parent || + this.permissions.update_remove_property || + this.permissions.update_add_property || + this.permissions.update_name || + this.permissions.update_data_type || + this.permissions.update_query_template_definition || + this.permissions.update_remove_file || + this.permissions.update_add_file || + this.permissions.update_move_file; + } + + impliesOwnership() { + return this.grant && !this.isOtherRole() && !this.isOwnerRole() && this.permissions.edit_acl; + } + + isOtherRole() { + return this.role === "?OTHER?"; + } + + isOwnerRole() { + return this.role === "?OWNER?"; + } +} + +export class EntityACL { + constructor({ + id, + acis, + current_permissions + }) { + this.id = id; + this.acis = acis || []; + this.current_permissions = current_permissions || {} + } + + getOwners() { + return this.acis.filter(aci => aci.impliesOwnership()).map(aci => aci.role); + } + +} + +const mappingJsToProtoPermissions = { + "retrieve_entity": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_ENTITY, + "retrieve_acl": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_ACL, + "retrieve_history": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_HISTORY, + "retrieve_owner": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_OWNER, + "retrieve_file": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_FILE, + "delete_entity": api.v1.EntityPermission.ENTITY_PERMISSION_DELETE, + "edit_acl": api.v1.EntityPermission.ENTITY_PERMISSION_EDIT_ACL, + "update_description": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_DESCRIPTION, + "update_value": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_VALUE, + "update_role": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ROLE, + "update_remove_parent": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_PARENT, + "update_add_parent": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_PARENT, + "update_remove_property": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_PROPERTY, + "update_add_property": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_PROPERTY, + "update_name": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_NAME, + "update_data_type": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_DATA_TYPE, + "update_query_template_definition": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_QUERY_TEMPLATE_DEFINITION, + "update_remove_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_FILE, + "update_add_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_FILE, + "update_move_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_MOVE_FILE, + "use_as_reference": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_REFERENCE, + "use_as_property": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_PROPERTY, + "use_as_parent": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_PARENT, + "use_as_data_type": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_DATA_TYPE, +} + +// produces the reversed dict from mappingJsToProtoPermissions +const mappingProtoPermissionsToJs = (() => { + const result = {} + Object.keys(mappingJsToProtoPermissions).forEach(key => { + result[mappingJsToProtoPermissions[key]] = key; + }); + return result; +})(); + +export function convertMessageToEntityPermissions(message) { + const permissions = {}; + for (let p of message) { + permissions[mappingProtoPermissionsToJs[p]] = true; + } + return permissions; + +} + +export function convertMessageToEntityPermissionRuleCapabilities(message) { + const capabilities = {}; + for (let c of message) { + if (c === api.v1.EntityPermissionRuleCapability.ENTITY_PERMISSION_RULE_CAPABILITY_DELETE) { + capabilities.delete_aci = true; + } + } + return capabilities; +} + +export function convertMessageToEntityACI(message) { + const role = message.getRole(); + const grant = message.getGrant(); + const priority = message.getPriority(); + const permissions = message.getPermissionsList(); + const capabilities = message.getCapabilitiesList(); + const aci = new EntityACI({ + role: role, + grant: grant, + priority: priority + }); + aci.permissions = convertMessageToEntityPermissions(permissions); + aci.capabilities = convertMessageToEntityPermissionRuleCapabilities(capabilities); + return aci; +} + +export function convertMessageToEntityAclPermission(message) { + const permissions = { + "edit_acl": false, + "edit_priority_acl": false, + }; + + if (message === api.v1.EntityAclPermission.ENTITY_ACL_PERMISSION_EDIT_ACL) { + permissions.edit_acl = true; + } else if (message === api.v1.EntityAclPermission.ENTITY_ACL_PERMISSION_EDIT_PRIORITY_ACL) { + permissions.edit_acl = true; + permissions.edit_priority_acl = true; + } + + return permissions; +} + +export function convertMessageToEntityACL(message) { + const id = message.getId(); + const acis = message.getRulesList(); + const permission = message.getPermission(); + return new EntityACL({ + id: id, + acis: acis.map(convertMessageToEntityACI), + current_permissions: convertMessageToEntityAclPermission(permission) + }); +} + +export function convertEntityAciToMessage(aci) { + const result = new api.v1.EntityPermissionRule(); + result.setRole(aci.role); + result.setPriority(aci.priority); + result.setGrant(aci.grant); + result.setPermissionsList(Object.keys(aci.permissions) + .filter(key => aci.permissions[key] && mappingJsToProtoPermissions[key]) + .map(key => { + return mappingJsToProtoPermissions[key]; + })); + return result; +} + +export function convertEntityAclToMessage(acl) { + const result = new api.v1.EntityACL(); + result.setId(acl.id); + result.setRulesList(acl.acis.map(convertEntityAciToMessage)); + return result; +} diff --git a/src/TransactionService.js b/src/TransactionService.js index 53e5cd5688e154cdf882557d0d654aa93c1f8c36..14533131a496ed83d48fb6b3a33953ad12733699 100644 --- a/src/TransactionService.js +++ b/src/TransactionService.js @@ -1,8 +1,9 @@ /* * This file is a part of the CaosDB Project. * - * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com> + * Copyright (C) 2021-2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021-2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> + * Copyright (C) 2021-2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free @@ -20,6 +21,10 @@ import { api } from "./EntityApi"; +import { + convertMessageToEntityACL, + convertEntityAclToMessage +} from "./EntityACL" export class TransactionService { @@ -84,4 +89,26 @@ export class TransactionService { const queryRequest = this._CreateQueryRequest(query); return new Promise(this._PrepareTransaction(queryRequest)); } + + async retrieveEntityAcl(id) { + const client = new api.v1.EntityTransactionServicePromiseClient(this.uri, null, null); + const request = new api.v1.MultiRetrieveEntityACLRequest(); + request.addId(id); + const response = await client.multiRetrieveEntityACL(request, {}); + + return convertMessageToEntityACL(response.getAclsList()[0]); + } + + async updateEntityAcl(acl) { + const updateAcl = convertEntityAclToMessage(acl); + + const client = new api.v1.EntityTransactionServicePromiseClient(this.uri, null, null); + const request = new api.v1.MultiUpdateEntityACLRequest(); + request.setAclsList([updateAcl]); + + const response = await client.multiUpdateEntityACL(request, {}); + return response; + } + + } diff --git a/src/index.js b/src/index.js index 3bf2d0d958637ce1a46eb8f4e26a3514e183ac0f..3c1a771dff5a234243d1dbc2774703e2d5ab48e8 100644 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,12 @@ export { } from "./Entity"; +export { + EntityACI, + EntityACL +} +from "./EntityACL"; + export { Property }