| 
									
										
										
										
											2020-05-18 19:54:43 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 13:51:12 +02:00
										 |  |  | const { yup } = require('@strapi/utils'); | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  | const _ = require('lodash'); | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  | const { isEmpty, has, isNil, isArray } = require('lodash/fp'); | 
					
						
							|  |  |  | const { getService } = require('../utils'); | 
					
						
							| 
									
										
										
										
											2020-08-11 18:16:39 +02:00
										 |  |  | const actionDomain = require('../domain/action'); | 
					
						
							| 
									
										
										
										
											2020-07-01 11:51:37 +02:00
										 |  |  | const { | 
					
						
							|  |  |  |   checkFieldsAreCorrectlyNested, | 
					
						
							|  |  |  |   checkFieldsDontHaveDuplicates, | 
					
						
							|  |  |  | } = require('./common-functions'); | 
					
						
							| 
									
										
										
										
											2020-05-18 19:54:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  | const getActionFromProvider = actionId => { | 
					
						
							|  |  |  |   return getService('permission').actionProvider.get(actionId); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | const email = yup | 
					
						
							|  |  |  |   .string() | 
					
						
							|  |  |  |   .email() | 
					
						
							| 
									
										
										
										
											2020-09-14 02:30:12 -05:00
										 |  |  |   .lowercase(); | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const firstname = yup.string().min(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const lastname = yup.string().min(1); | 
					
						
							| 
									
										
										
										
											2020-05-18 19:54:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | const username = yup.string().min(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const password = yup | 
					
						
							|  |  |  |   .string() | 
					
						
							|  |  |  |   .min(8) | 
					
						
							|  |  |  |   .matches(/[a-z]/, '${path} must contain at least one lowercase character') | 
					
						
							|  |  |  |   .matches(/[A-Z]/, '${path} must contain at least one uppercase character') | 
					
						
							|  |  |  |   .matches(/\d/, '${path} must contain at least one number'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 16:56:44 +02:00
										 |  |  | const roles = yup.array(yup.strapiID()).min(1); | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  | const isAPluginName = yup | 
					
						
							|  |  |  |   .string() | 
					
						
							|  |  |  |   .test('is-a-plugin-name', 'is not a plugin name', function(value) { | 
					
						
							|  |  |  |     return [undefined, 'admin', ...Object.keys(strapi.plugins)].includes(value) | 
					
						
							|  |  |  |       ? true | 
					
						
							|  |  |  |       : this.createError({ path: this.path, message: `${this.path} is not an existing plugin` }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 11:40:50 +02:00
										 |  |  | const arrayOfConditionNames = yup | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |   .array() | 
					
						
							|  |  |  |   .of(yup.string()) | 
					
						
							|  |  |  |   .test('is-an-array-of-conditions', 'is not a plugin name', function(value) { | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |     const ids = strapi.admin.services.permission.conditionProvider.keys(); | 
					
						
							| 
									
										
										
										
											2020-06-15 19:11:36 +02:00
										 |  |  |     return _.isUndefined(value) || _.difference(value, ids).length === 0 | 
					
						
							|  |  |  |       ? true | 
					
						
							|  |  |  |       : this.createError({ path: this.path, message: `contains conditions that don't exist` }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  | const permissionsAreEquals = (a, b) => | 
					
						
							|  |  |  |   a.action === b.action && (a.subject === b.subject || (_.isNil(a.subject) && _.isNil(b.subject))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const checkNoDuplicatedPermissions = permissions => | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |   !Array.isArray(permissions) || | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  |   permissions.every((permA, i) => | 
					
						
							|  |  |  |     permissions.slice(i + 1).every(permB => !permissionsAreEquals(permA, permB)) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  | const checkNilFields = action => | 
					
						
							|  |  |  |   function(fields) { | 
					
						
							|  |  |  |     // If the parent has no action field, then we ignore this test
 | 
					
						
							|  |  |  |     if (isNil(action)) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return actionDomain.appliesToProperty('fields', action) || isNil(fields); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const fieldsPropertyValidation = action => | 
					
						
							|  |  |  |   yup | 
					
						
							|  |  |  |     .array() | 
					
						
							|  |  |  |     .of(yup.string()) | 
					
						
							|  |  |  |     .nullable() | 
					
						
							|  |  |  |     .test( | 
					
						
							|  |  |  |       'field-nested', | 
					
						
							|  |  |  |       'Fields format are incorrect (bad nesting).', | 
					
						
							|  |  |  |       checkFieldsAreCorrectlyNested | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     .test( | 
					
						
							|  |  |  |       'field-nested', | 
					
						
							|  |  |  |       'Fields format are incorrect (duplicates).', | 
					
						
							|  |  |  |       checkFieldsDontHaveDuplicates | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     .test( | 
					
						
							|  |  |  |       'fields-restriction', | 
					
						
							|  |  |  |       'The permission at ${path} must have fields set to null or undefined', | 
					
						
							|  |  |  |       checkNilFields(action) | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2020-08-14 16:31:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  | const updatePermissions = yup | 
					
						
							|  |  |  |   .object() | 
					
						
							|  |  |  |   .shape({ | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  |     permissions: yup | 
					
						
							|  |  |  |       .array() | 
					
						
							| 
									
										
										
										
											2021-06-17 09:55:32 +02:00
										 |  |  |       .required() | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |       .of( | 
					
						
							|  |  |  |         yup | 
					
						
							|  |  |  |           .object() | 
					
						
							|  |  |  |           .shape({ | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |             action: yup | 
					
						
							|  |  |  |               .string() | 
					
						
							|  |  |  |               .required() | 
					
						
							|  |  |  |               .test('action-validity', 'action is not an existing permission action', function( | 
					
						
							|  |  |  |                 actionId | 
					
						
							|  |  |  |               ) { | 
					
						
							|  |  |  |                 // If the action field is Nil, ignore the test and let the required check handle the error
 | 
					
						
							|  |  |  |                 if (isNil(actionId)) { | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return !!getActionFromProvider(actionId); | 
					
						
							|  |  |  |               }), | 
					
						
							|  |  |  |             subject: yup | 
					
						
							|  |  |  |               .string() | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |               .nullable() | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |               .test('subject-validity', 'Invalid subject submitted', function(subject) { | 
					
						
							|  |  |  |                 const action = getActionFromProvider(this.options.parent.action); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!action) { | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (isNil(action.subjects)) { | 
					
						
							|  |  |  |                   return isNil(subject); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (isArray(action.subjects)) { | 
					
						
							|  |  |  |                   return action.subjects.includes(subject); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |               }), | 
					
						
							|  |  |  |             properties: yup | 
					
						
							|  |  |  |               .object() | 
					
						
							|  |  |  |               .test('properties-structure', 'Invalid property set at ${path}', function( | 
					
						
							|  |  |  |                 properties | 
					
						
							|  |  |  |               ) { | 
					
						
							|  |  |  |                 const action = getActionFromProvider(this.options.parent.action); | 
					
						
							|  |  |  |                 const hasNoProperties = isEmpty(properties) || isNil(properties); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!has('options.applyToProperties', action)) { | 
					
						
							|  |  |  |                   return hasNoProperties; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (hasNoProperties) { | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const { applyToProperties } = action.options; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!isArray(applyToProperties)) { | 
					
						
							|  |  |  |                   return false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return Object.keys(properties).every(property => | 
					
						
							|  |  |  |                   applyToProperties.includes(property) | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |               }) | 
					
						
							|  |  |  |               .test('fields-property', 'Invalid fields property at ${path}', async function( | 
					
						
							|  |  |  |                 properties = {} | 
					
						
							|  |  |  |               ) { | 
					
						
							|  |  |  |                 const action = getActionFromProvider(this.options.parent.action); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!action || !properties) { | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!actionDomain.appliesToProperty('fields', action)) { | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 try { | 
					
						
							|  |  |  |                   await fieldsPropertyValidation(action).validate(properties.fields, { | 
					
						
							|  |  |  |                     strict: true, | 
					
						
							|  |  |  |                     abortEarly: false, | 
					
						
							|  |  |  |                   }); | 
					
						
							|  |  |  |                   return true; | 
					
						
							|  |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                   // Propagate fieldsPropertyValidation error with updated path
 | 
					
						
							|  |  |  |                   throw this.createError({ | 
					
						
							|  |  |  |                     message: e.message, | 
					
						
							|  |  |  |                     path: `${this.path}.fields`, | 
					
						
							|  |  |  |                   }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |               }), | 
					
						
							| 
									
										
										
										
											2020-07-20 17:40:01 +02:00
										 |  |  |             conditions: yup.array().of(yup.string()), | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |           }) | 
					
						
							|  |  |  |           .noUnknown() | 
					
						
							| 
									
										
										
										
											2020-08-13 14:15:25 +02:00
										 |  |  |       ) | 
					
						
							|  |  |  |       .test( | 
					
						
							| 
									
										
										
										
											2020-08-14 16:31:36 +02:00
										 |  |  |         'duplicated-permissions', | 
					
						
							| 
									
										
										
										
											2020-08-13 14:15:25 +02:00
										 |  |  |         'Some permissions are duplicated (same action and subject)', | 
					
						
							|  |  |  |         checkNoDuplicatedPermissions | 
					
						
							| 
									
										
										
										
											2020-07-03 18:33:38 +02:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |   }) | 
					
						
							|  |  |  |   .required() | 
					
						
							|  |  |  |   .noUnknown(); | 
					
						
							| 
									
										
										
										
											2020-06-23 16:31:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | module.exports = { | 
					
						
							|  |  |  |   email, | 
					
						
							|  |  |  |   firstname, | 
					
						
							|  |  |  |   lastname, | 
					
						
							|  |  |  |   username, | 
					
						
							|  |  |  |   password, | 
					
						
							|  |  |  |   roles, | 
					
						
							| 
									
										
										
										
											2020-06-09 17:45:53 +02:00
										 |  |  |   isAPluginName, | 
					
						
							| 
									
										
										
										
											2020-06-18 11:40:50 +02:00
										 |  |  |   arrayOfConditionNames, | 
					
						
							| 
									
										
										
										
											2020-07-06 09:56:37 +02:00
										 |  |  |   updatePermissions, | 
					
						
							| 
									
										
										
										
											2020-05-27 16:06:15 +02:00
										 |  |  | }; |