| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  | const _ = require('lodash'); | 
					
						
							| 
									
										
										
										
											2021-04-29 13:51:12 +02:00
										 |  |  | const { yup, formatYupErrors } = require('@strapi/utils'); | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  | const { getService } = require('../utils'); | 
					
						
							| 
									
										
										
										
											2020-10-05 16:26:55 +02:00
										 |  |  | const { AUTHOR_CODE, PUBLISH_ACTION } = require('../services/constants'); | 
					
						
							|  |  |  | const { | 
					
						
							|  |  |  |   BOUND_ACTIONS_FOR_FIELDS, | 
					
						
							|  |  |  |   BOUND_ACTIONS, | 
					
						
							|  |  |  |   getBoundActionsBySubject, | 
					
						
							|  |  |  | } = require('../domain/role'); | 
					
						
							| 
									
										
										
										
											2020-10-27 11:27:17 +01:00
										 |  |  | const validators = require('./common-validators'); | 
					
						
							| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const handleReject = error => Promise.reject(formatYupErrors(error)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 15:42:32 +02:00
										 |  |  | // validatedUpdatePermissionsInput
 | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  | const actionFieldsAreEqual = (a, b) => { | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |   const aFields = a.properties.fields || []; | 
					
						
							|  |  |  |   const bFields = b.properties.fields || []; | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return _.isEqual(aFields.sort(), bFields.sort()); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const haveSameFieldsAsOtherActions = (a, i, allActions) => | 
					
						
							|  |  |  |   allActions.slice(i + 1).every(b => actionFieldsAreEqual(a, b)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  | const checkPermissionsAreBound = role => | 
					
						
							|  |  |  |   function(permissions) { | 
					
						
							|  |  |  |     const permsBySubject = _.groupBy( | 
					
						
							|  |  |  |       permissions.filter(perm => BOUND_ACTIONS.includes(perm.action)), | 
					
						
							|  |  |  |       'subject' | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const [subject, perms] of Object.entries(permsBySubject)) { | 
					
						
							|  |  |  |       const boundActions = getBoundActionsBySubject(role, subject); | 
					
						
							|  |  |  |       const missingActions = | 
					
						
							|  |  |  |         _.xor( | 
					
						
							|  |  |  |           perms.map(p => p.action), | 
					
						
							|  |  |  |           boundActions | 
					
						
							|  |  |  |         ).length !== 0; | 
					
						
							|  |  |  |       if (missingActions) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const permsBoundByFields = perms.filter(p => BOUND_ACTIONS_FOR_FIELDS.includes(p.action)); | 
					
						
							|  |  |  |       const everyActionsHaveSameFields = _.every(permsBoundByFields, haveSameFieldsAsOtherActions); | 
					
						
							|  |  |  |       if (!everyActionsHaveSameFields) return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const noPublishPermissionForAuthorRole = role => | 
					
						
							|  |  |  |   function(permissions) { | 
					
						
							|  |  |  |     const isAuthor = role.code === AUTHOR_CODE; | 
					
						
							|  |  |  |     const hasPublishPermission = permissions.some(perm => perm.action === PUBLISH_ACTION); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return !(isAuthor && hasPublishPermission); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  | const getUpdatePermissionsSchemas = role => [ | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |   validators.updatePermissions, | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  |   yup.object().shape({ permissions: actionsExistSchema.clone() }), | 
					
						
							|  |  |  |   yup.object().shape({ | 
					
						
							|  |  |  |     permissions: yup | 
					
						
							|  |  |  |       .array() | 
					
						
							|  |  |  |       .test( | 
					
						
							|  |  |  |         'author-no-publish', | 
					
						
							|  |  |  |         'The author role cannot have the publish permission.', | 
					
						
							|  |  |  |         noPublishPermissionForAuthorRole(role) | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |   }), | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   yup.object().shape({ | 
					
						
							| 
									
										
										
										
											2020-05-28 13:02:06 +02:00
										 |  |  |     permissions: yup | 
					
						
							|  |  |  |       .array() | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |       .test( | 
					
						
							|  |  |  |         'are-bond', | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  |         'Permissions have to be defined all together for a subject field or not at all', | 
					
						
							|  |  |  |         checkPermissionsAreBound(role) | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   }), | 
					
						
							|  |  |  | ]; | 
					
						
							| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 18:04:47 +02:00
										 |  |  | const checkPermissionsSchema = yup.object().shape({ | 
					
						
							|  |  |  |   permissions: yup.array().of( | 
					
						
							|  |  |  |     yup | 
					
						
							|  |  |  |       .object() | 
					
						
							|  |  |  |       .shape({ | 
					
						
							|  |  |  |         action: yup.string().required(), | 
					
						
							|  |  |  |         subject: yup.string(), | 
					
						
							|  |  |  |         field: yup.string(), | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       .noUnknown() | 
					
						
							|  |  |  |   ), | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const validateCheckPermissionsInput = data => { | 
					
						
							|  |  |  |   return checkPermissionsSchema | 
					
						
							|  |  |  |     .validate(data, { strict: true, abortEarly: false }) | 
					
						
							|  |  |  |     .catch(handleReject); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  | const validatedUpdatePermissionsInput = async (permissions, role) => { | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2020-10-02 18:34:13 +02:00
										 |  |  |     const schemas = getUpdatePermissionsSchemas(role); | 
					
						
							|  |  |  |     for (const schema of schemas) { | 
					
						
							|  |  |  |       await schema.validate(permissions, { strict: true, abortEarly: false }); | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							| 
									
										
										
										
											2020-06-18 18:10:12 +02:00
										 |  |  |     return handleReject(e); | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 15:42:32 +02:00
										 |  |  | // validatePermissionsExist
 | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const checkPermissionsExist = function(permissions) { | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |   const existingActions = getService('permission').actionProvider.values(); | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |   const failIndex = permissions.findIndex( | 
					
						
							|  |  |  |     permission => | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |       !existingActions.some( | 
					
						
							| 
									
										
										
										
											2020-08-11 18:16:39 +02:00
										 |  |  |         action => | 
					
						
							|  |  |  |           action.actionId === permission.action && | 
					
						
							|  |  |  |           (action.section !== 'contentTypes' || action.subjects.includes(permission.subject)) | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |       ) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return failIndex === -1 | 
					
						
							|  |  |  |     ? true | 
					
						
							|  |  |  |     : this.createError({ | 
					
						
							|  |  |  |         path: 'permissions', | 
					
						
							|  |  |  |         message: `[${failIndex}] is not an existing permission action`, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const actionsExistSchema = yup | 
					
						
							|  |  |  |   .array() | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   .of( | 
					
						
							|  |  |  |     yup.object().shape({ | 
					
						
							| 
									
										
										
										
											2020-07-20 17:40:01 +02:00
										 |  |  |       conditions: yup.array().of(yup.string()), | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |     }) | 
					
						
							|  |  |  |   ) | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |   .test('actions-exist', '', checkPermissionsExist); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const validatePermissionsExist = data => { | 
					
						
							|  |  |  |   return actionsExistSchema.validate(data, { strict: true, abortEarly: false }).catch(handleReject); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // exports
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | module.exports = { | 
					
						
							|  |  |  |   validatedUpdatePermissionsInput, | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |   validatePermissionsExist, | 
					
						
							| 
									
										
										
										
											2020-06-10 18:04:47 +02:00
										 |  |  |   validateCheckPermissionsInput, | 
					
						
							| 
									
										
										
										
											2020-05-28 11:29:59 +02:00
										 |  |  | }; |