@strapi/plugin-users-permissions 4.0.0-next.6 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
  2. package/admin/src/components/BoundRoute/index.js +40 -24
  3. package/admin/src/components/FormModal/Input/index.js +121 -0
  4. package/admin/src/components/FormModal/index.js +123 -0
  5. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +19 -26
  6. package/admin/src/components/Permissions/PermissionRow/SubCategory.js +118 -0
  7. package/admin/src/components/Permissions/PermissionRow/index.js +9 -48
  8. package/admin/src/components/Permissions/index.js +36 -24
  9. package/admin/src/components/Permissions/init.js +1 -6
  10. package/admin/src/components/Policies/index.js +46 -47
  11. package/admin/src/components/UsersPermissions/index.js +29 -26
  12. package/admin/src/components/UsersPermissions/init.js +1 -2
  13. package/admin/src/hooks/useFetchRole/index.js +17 -7
  14. package/admin/src/hooks/useForm/index.js +3 -29
  15. package/admin/src/hooks/useForm/reducer.js +2 -21
  16. package/admin/src/hooks/usePlugins/index.js +12 -21
  17. package/admin/src/hooks/usePlugins/reducer.js +0 -3
  18. package/admin/src/index.js +29 -34
  19. package/admin/src/pages/AdvancedSettings/index.js +210 -193
  20. package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
  21. package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
  22. package/admin/src/pages/AdvancedSettings/utils/schema.js +22 -0
  23. package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
  24. package/admin/src/pages/EmailTemplates/components/EmailTable.js +116 -0
  25. package/admin/src/pages/EmailTemplates/index.js +125 -198
  26. package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
  27. package/admin/src/pages/Providers/index.js +208 -216
  28. package/admin/src/pages/Providers/utils/api.js +21 -0
  29. package/admin/src/pages/Providers/utils/forms.js +168 -126
  30. package/admin/src/pages/Roles/CreatePage/index.js +155 -147
  31. package/admin/src/pages/Roles/EditPage/index.js +162 -134
  32. package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
  33. package/admin/src/pages/Roles/ListPage/index.js +176 -156
  34. package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
  35. package/admin/src/pages/Roles/index.js +14 -8
  36. package/admin/src/permissions.js +12 -14
  37. package/admin/src/translations/ar.json +0 -8
  38. package/admin/src/translations/cs.json +0 -8
  39. package/admin/src/translations/de.json +0 -8
  40. package/admin/src/translations/dk.json +0 -8
  41. package/admin/src/translations/en.json +33 -12
  42. package/admin/src/translations/es.json +0 -8
  43. package/admin/src/translations/fr.json +0 -8
  44. package/admin/src/translations/id.json +0 -8
  45. package/admin/src/translations/it.json +0 -8
  46. package/admin/src/translations/ja.json +0 -8
  47. package/admin/src/translations/ko.json +0 -8
  48. package/admin/src/translations/ms.json +0 -8
  49. package/admin/src/translations/nl.json +0 -8
  50. package/admin/src/translations/pl.json +0 -8
  51. package/admin/src/translations/pt-BR.json +0 -8
  52. package/admin/src/translations/pt.json +0 -8
  53. package/admin/src/translations/ru.json +0 -8
  54. package/admin/src/translations/sk.json +0 -8
  55. package/admin/src/translations/sv.json +0 -8
  56. package/admin/src/translations/th.json +0 -8
  57. package/admin/src/translations/tr.json +0 -8
  58. package/admin/src/translations/uk.json +0 -8
  59. package/admin/src/translations/vi.json +0 -8
  60. package/admin/src/translations/zh-Hans.json +5 -14
  61. package/admin/src/translations/zh.json +0 -8
  62. package/admin/src/utils/axiosInstance.js +36 -0
  63. package/admin/src/utils/formatPluginName.js +26 -0
  64. package/admin/src/utils/index.js +1 -0
  65. package/documentation/1.0.0/overrides/users-permissions-Role.json +6 -6
  66. package/documentation/1.0.0/overrides/users-permissions-User.json +7 -7
  67. package/package.json +30 -29
  68. package/{config/functions/bootstrap.js → server/bootstrap/index.js} +26 -33
  69. package/{config → server/bootstrap}/users-permissions-actions.js +0 -0
  70. package/server/config.js +23 -0
  71. package/server/content-types/index.js +11 -0
  72. package/server/content-types/permission/index.js +34 -0
  73. package/server/content-types/role/index.js +51 -0
  74. package/server/content-types/user/index.js +72 -0
  75. package/{models/User.config.js → server/content-types/user/schema-config.js} +0 -0
  76. package/server/controllers/auth.js +440 -0
  77. package/server/controllers/content-manager-user.js +183 -0
  78. package/server/controllers/index.js +17 -0
  79. package/server/controllers/permissions.js +26 -0
  80. package/server/controllers/role.js +77 -0
  81. package/server/controllers/settings.js +85 -0
  82. package/server/controllers/user.js +191 -0
  83. package/server/controllers/validation/auth.js +29 -0
  84. package/{controllers → server/controllers}/validation/email-template.js +0 -0
  85. package/server/controllers/validation/user.js +38 -0
  86. package/server/graphql/index.js +44 -0
  87. package/server/graphql/mutations/auth/email-confirmation.js +39 -0
  88. package/server/graphql/mutations/auth/forgot-password.js +38 -0
  89. package/server/graphql/mutations/auth/login.js +38 -0
  90. package/server/graphql/mutations/auth/register.js +39 -0
  91. package/server/graphql/mutations/auth/reset-password.js +41 -0
  92. package/server/graphql/mutations/crud/role/create-role.js +37 -0
  93. package/server/graphql/mutations/crud/role/delete-role.js +28 -0
  94. package/server/graphql/mutations/crud/role/update-role.js +38 -0
  95. package/server/graphql/mutations/crud/user/create-user.js +48 -0
  96. package/server/graphql/mutations/crud/user/delete-user.js +42 -0
  97. package/server/graphql/mutations/crud/user/update-user.js +49 -0
  98. package/server/graphql/mutations/index.js +42 -0
  99. package/server/graphql/queries/index.js +13 -0
  100. package/server/graphql/queries/me.js +17 -0
  101. package/server/graphql/resolvers-configs.js +37 -0
  102. package/server/graphql/types/create-role-payload.js +11 -0
  103. package/server/graphql/types/delete-role-payload.js +11 -0
  104. package/server/graphql/types/index.js +21 -0
  105. package/server/graphql/types/login-input.js +13 -0
  106. package/server/graphql/types/login-payload.js +12 -0
  107. package/server/graphql/types/me-role.js +14 -0
  108. package/server/graphql/types/me.js +16 -0
  109. package/server/graphql/types/password-payload.js +11 -0
  110. package/server/graphql/types/register-input.js +13 -0
  111. package/server/graphql/types/update-role-payload.js +11 -0
  112. package/server/graphql/utils.js +27 -0
  113. package/server/index.js +21 -0
  114. package/server/middlewares/index.js +7 -0
  115. package/{config/policies → server/middlewares}/rateLimit.js +4 -8
  116. package/server/register.js +11 -0
  117. package/server/routes/admin/index.js +10 -0
  118. package/server/routes/admin/permissions.js +20 -0
  119. package/server/routes/admin/role.js +79 -0
  120. package/server/routes/admin/settings.js +95 -0
  121. package/server/routes/content-api/auth.js +73 -0
  122. package/server/routes/content-api/index.js +11 -0
  123. package/server/routes/content-api/permissions.js +9 -0
  124. package/server/routes/content-api/role.js +29 -0
  125. package/server/routes/content-api/user.js +61 -0
  126. package/server/routes/index.js +6 -0
  127. package/server/services/index.js +15 -0
  128. package/server/services/jwt.js +55 -0
  129. package/server/services/providers.js +599 -0
  130. package/server/services/role.js +177 -0
  131. package/{services → server/services}/user.js +32 -35
  132. package/server/services/users-permissions.js +233 -0
  133. package/server/strategies/users-permissions.js +123 -0
  134. package/{utils → server/utils}/index.d.ts +6 -1
  135. package/server/utils/index.js +9 -0
  136. package/strapi-admin.js +3 -0
  137. package/strapi-server.js +3 -0
  138. package/admin/src/assets/images/logo.svg +0 -1
  139. package/admin/src/components/BaselineAlignement/index.js +0 -33
  140. package/admin/src/components/Bloc/index.js +0 -10
  141. package/admin/src/components/BoundRoute/Components.js +0 -78
  142. package/admin/src/components/ContainerFluid/index.js +0 -13
  143. package/admin/src/components/FormBloc/index.js +0 -61
  144. package/admin/src/components/IntlInput/index.js +0 -38
  145. package/admin/src/components/ListBaselineAlignment/index.js +0 -8
  146. package/admin/src/components/ListRow/Components.js +0 -74
  147. package/admin/src/components/ListRow/index.js +0 -35
  148. package/admin/src/components/ModalForm/Wrapper.js +0 -12
  149. package/admin/src/components/ModalForm/index.js +0 -59
  150. package/admin/src/components/Permissions/ListWrapper.js +0 -9
  151. package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +0 -7
  152. package/admin/src/components/Permissions/PermissionRow/RowStyle.js +0 -28
  153. package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +0 -13
  154. package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +0 -8
  155. package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +0 -26
  156. package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +0 -116
  157. package/admin/src/components/Policies/Components.js +0 -26
  158. package/admin/src/components/PrefixedIcon/index.js +0 -27
  159. package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +0 -7
  160. package/admin/src/components/Roles/EmptyRole/index.js +0 -27
  161. package/admin/src/components/Roles/RoleListWrapper/index.js +0 -17
  162. package/admin/src/components/Roles/RoleRow/RoleDescription.js +0 -9
  163. package/admin/src/components/Roles/RoleRow/index.js +0 -45
  164. package/admin/src/components/Roles/index.js +0 -3
  165. package/admin/src/components/SizedInput/index.js +0 -24
  166. package/admin/src/pages/AdvancedSettings/reducer.js +0 -65
  167. package/admin/src/pages/AdvancedSettings/utils/form.js +0 -52
  168. package/admin/src/pages/EmailTemplates/CustomTextInput.js +0 -105
  169. package/admin/src/pages/EmailTemplates/Wrapper.js +0 -36
  170. package/admin/src/pages/EmailTemplates/reducer.js +0 -58
  171. package/admin/src/pages/EmailTemplates/utils/forms.js +0 -81
  172. package/admin/src/pages/Roles/ListPage/BaselineAlignment.js +0 -8
  173. package/config/layout.js +0 -10
  174. package/config/policies/isAuthenticated.js +0 -9
  175. package/config/policies/permissions.js +0 -94
  176. package/config/request.json +0 -6
  177. package/config/routes.json +0 -381
  178. package/config/schema.graphql.js +0 -284
  179. package/config/security.json +0 -5
  180. package/controllers/auth.js +0 -596
  181. package/controllers/user/admin.js +0 -230
  182. package/controllers/user/api.js +0 -174
  183. package/controllers/user.js +0 -117
  184. package/controllers/users-permissions.js +0 -271
  185. package/middlewares/users-permissions/defaults.json +0 -5
  186. package/middlewares/users-permissions/index.js +0 -40
  187. package/models/Permission.js +0 -7
  188. package/models/Permission.settings.json +0 -45
  189. package/models/Role.js +0 -7
  190. package/models/Role.settings.json +0 -43
  191. package/models/User.js +0 -7
  192. package/models/User.settings.json +0 -63
  193. package/services/jwt.js +0 -65
  194. package/services/providers.js +0 -598
  195. package/services/users-permissions.js +0 -429
  196. package/utils/index.js +0 -11
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const { NotFoundError } = require('@strapi/utils').errors;
5
+ const { getService } = require('../utils');
6
+
7
+ module.exports = ({ strapi }) => ({
8
+ async createRole(params) {
9
+ if (!params.type) {
10
+ params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
11
+ }
12
+
13
+ const role = await strapi
14
+ .query('plugin::users-permissions.role')
15
+ .create({ data: _.omit(params, ['users', 'permissions']) });
16
+
17
+ const createPromises = _.flatMap(params.permissions, (type, typeName) => {
18
+ return _.flatMap(type.controllers, (controller, controllerName) => {
19
+ return _.reduce(
20
+ controller,
21
+ (acc, action, actionName) => {
22
+ const { enabled /* policy */ } = action;
23
+
24
+ if (enabled) {
25
+ const actionID = `${typeName}.${controllerName}.${actionName}`;
26
+
27
+ acc.push(
28
+ strapi
29
+ .query('plugin::users-permissions.permission')
30
+ .create({ data: { action: actionID, role: role.id } })
31
+ );
32
+ }
33
+
34
+ return acc;
35
+ },
36
+ []
37
+ );
38
+ });
39
+ });
40
+
41
+ await Promise.all(createPromises);
42
+ },
43
+
44
+ async getRole(roleID) {
45
+ const role = await strapi
46
+ .query('plugin::users-permissions.role')
47
+ .findOne({ where: { id: roleID }, populate: ['permissions'] });
48
+
49
+ if (!role) {
50
+ throw new NotFoundError('Role not found');
51
+ }
52
+
53
+ const allActions = getService('users-permissions').getActions();
54
+
55
+ // Group by `type`.
56
+ role.permissions.forEach(permission => {
57
+ const [type, controller, action] = permission.action.split('.');
58
+
59
+ _.set(allActions, `${type}.controllers.${controller}.${action}`, {
60
+ enabled: true,
61
+ policy: '',
62
+ });
63
+ });
64
+
65
+ return {
66
+ ...role,
67
+ permissions: allActions,
68
+ };
69
+ },
70
+
71
+ async getRoles() {
72
+ const roles = await strapi.query('plugin::users-permissions.role').findMany({ sort: ['name'] });
73
+
74
+ for (const role of roles) {
75
+ role.nb_users = await strapi
76
+ .query('plugin::users-permissions.user')
77
+ .count({ where: { role: { id: role.id } } });
78
+ }
79
+
80
+ return roles;
81
+ },
82
+
83
+ async updateRole(roleID, data) {
84
+ const role = await strapi
85
+ .query('plugin::users-permissions.role')
86
+ .findOne({ where: { id: roleID }, populate: ['permissions'] });
87
+
88
+ if (!role) {
89
+ throw new NotFoundError('Role not found');
90
+ }
91
+
92
+ await strapi.query('plugin::users-permissions.role').update({
93
+ where: { id: roleID },
94
+ data: _.pick(data, ['name', 'description']),
95
+ });
96
+
97
+ const { permissions } = data;
98
+
99
+ const newActions = _.flatMap(permissions, (type, typeName) => {
100
+ return _.flatMap(type.controllers, (controller, controllerName) => {
101
+ return _.reduce(
102
+ controller,
103
+ (acc, action, actionName) => {
104
+ const { enabled /* policy */ } = action;
105
+
106
+ if (enabled) {
107
+ acc.push(`${typeName}.${controllerName}.${actionName}`);
108
+ }
109
+
110
+ return acc;
111
+ },
112
+ []
113
+ );
114
+ });
115
+ });
116
+
117
+ const oldActions = role.permissions.map(({ action }) => action);
118
+
119
+ const toDelete = role.permissions.reduce((acc, permission) => {
120
+ if (!newActions.includes(permission.action)) {
121
+ acc.push(permission);
122
+ }
123
+ return acc;
124
+ }, []);
125
+
126
+ const toCreate = newActions
127
+ .filter(action => !oldActions.includes(action))
128
+ .map(action => ({ action, role: role.id }));
129
+
130
+ await Promise.all(
131
+ toDelete.map(permission =>
132
+ strapi
133
+ .query('plugin::users-permissions.permission')
134
+ .delete({ where: { id: permission.id } })
135
+ )
136
+ );
137
+
138
+ await Promise.all(
139
+ toCreate.map(permissionInfo =>
140
+ strapi.query('plugin::users-permissions.permission').create({ data: permissionInfo })
141
+ )
142
+ );
143
+ },
144
+
145
+ async deleteRole(roleID, publicRoleID) {
146
+ const role = await strapi
147
+ .query('plugin::users-permissions.role')
148
+ .findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
149
+
150
+ if (!role) {
151
+ throw new NotFoundError('Role not found');
152
+ }
153
+
154
+ // Move users to guest role.
155
+ await Promise.all(
156
+ role.users.map(user => {
157
+ return strapi.query('plugin::users-permissions.user').update({
158
+ where: { id: user.id },
159
+ data: { role: publicRoleID },
160
+ });
161
+ })
162
+ );
163
+
164
+ // Remove permissions related to this role.
165
+ // TODO: use delete many
166
+ await Promise.all(
167
+ role.permissions.map(permission => {
168
+ return strapi.query('plugin::users-permissions.permission').delete({
169
+ where: { id: permission.id },
170
+ });
171
+ })
172
+ );
173
+
174
+ // Delete the role.
175
+ await strapi.query('plugin::users-permissions.role').delete({ where: { id: roleID } });
176
+ },
177
+ });
@@ -9,10 +9,10 @@
9
9
  const crypto = require('crypto');
10
10
  const bcrypt = require('bcryptjs');
11
11
 
12
- const { sanitizeEntity, getAbsoluteServerUrl } = require('@strapi/utils');
12
+ const { getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
13
13
  const { getService } = require('../utils');
14
14
 
15
- module.exports = {
15
+ module.exports = ({ strapi }) => ({
16
16
  /**
17
17
  * Promise to count users
18
18
  *
@@ -20,7 +20,7 @@ module.exports = {
20
20
  */
21
21
 
22
22
  count(params) {
23
- return strapi.query('plugins::users-permissions.user').count({ where: params });
23
+ return strapi.query('plugin::users-permissions.user').count({ where: params });
24
24
  },
25
25
 
26
26
  /**
@@ -39,7 +39,7 @@ module.exports = {
39
39
  }
40
40
 
41
41
  return strapi
42
- .query('plugins::users-permissions.user')
42
+ .query('plugin::users-permissions.user')
43
43
  .create({ data: values, populate: ['role'] });
44
44
  },
45
45
 
@@ -53,7 +53,7 @@ module.exports = {
53
53
  }
54
54
 
55
55
  return strapi
56
- .query('plugins::users-permissions.user')
56
+ .query('plugin::users-permissions.user')
57
57
  .update({ where: params, data: values, populate: ['role'] });
58
58
  },
59
59
 
@@ -62,7 +62,7 @@ module.exports = {
62
62
  * @return {Promise}
63
63
  */
64
64
  fetch(params, populate) {
65
- return strapi.query('plugins::users-permissions.user').findOne({ where: params, populate });
65
+ return strapi.query('plugin::users-permissions.user').findOne({ where: params, populate });
66
66
  },
67
67
 
68
68
  /**
@@ -71,7 +71,7 @@ module.exports = {
71
71
  */
72
72
  fetchAuthenticatedUser(id) {
73
73
  return strapi
74
- .query('plugins::users-permissions.user')
74
+ .query('plugin::users-permissions.user')
75
75
  .findOne({ where: { id }, populate: ['role'] });
76
76
  },
77
77
 
@@ -80,7 +80,7 @@ module.exports = {
80
80
  * @return {Promise}
81
81
  */
82
82
  fetchAll(params, populate) {
83
- return strapi.query('plugins::users-permissions.user').findMany({ where: params, populate });
83
+ return strapi.query('plugin::users-permissions.user').findMany({ where: params, populate });
84
84
  },
85
85
 
86
86
  hashPassword(user = {}) {
@@ -111,11 +111,7 @@ module.exports = {
111
111
  * @return {Promise}
112
112
  */
113
113
  async remove(params) {
114
- return strapi.query('plugins::users-permissions.user').delete({ where: params });
115
- },
116
-
117
- async removeAll(params) {
118
- return strapi.query('plugins::users-permissions.user').delete({ where: params });
114
+ return strapi.query('plugin::users-permissions.user').delete({ where: params });
119
115
  },
120
116
 
121
117
  validatePassword(password, hash) {
@@ -124,19 +120,15 @@ module.exports = {
124
120
 
125
121
  async sendConfirmationEmail(user) {
126
122
  const userPermissionService = getService('users-permissions');
127
- const pluginStore = await strapi.store({
128
- environment: '',
129
- type: 'plugin',
130
- name: 'users-permissions',
131
- });
123
+ const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
124
+ const userSchema = strapi.getModel('plugin::users-permissions.user');
132
125
 
133
126
  const settings = await pluginStore
134
127
  .get({ key: 'email' })
135
128
  .then(storeEmail => storeEmail['email_confirmation'].options);
136
129
 
137
- const userInfo = sanitizeEntity(user, {
138
- model: strapi.getModel('plugins::users-permissions.user'),
139
- });
130
+ // Sanitize the template's user information
131
+ const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(userSchema, user);
140
132
 
141
133
  const confirmationToken = crypto.randomBytes(20).toString('hex');
142
134
 
@@ -144,23 +136,28 @@ module.exports = {
144
136
 
145
137
  settings.message = await userPermissionService.template(settings.message, {
146
138
  URL: `${getAbsoluteServerUrl(strapi.config)}/auth/email-confirmation`,
147
- USER: userInfo,
139
+ USER: sanitizedUserInfo,
148
140
  CODE: confirmationToken,
149
141
  });
150
142
 
151
- settings.object = await userPermissionService.template(settings.object, { USER: userInfo });
143
+ settings.object = await userPermissionService.template(settings.object, {
144
+ USER: sanitizedUserInfo,
145
+ });
152
146
 
153
147
  // Send an email to the user.
154
- await strapi.plugins['email'].services.email.send({
155
- to: user.email,
156
- from:
157
- settings.from.email && settings.from.name
158
- ? `${settings.from.name} <${settings.from.email}>`
159
- : undefined,
160
- replyTo: settings.response_email,
161
- subject: settings.object,
162
- text: settings.message,
163
- html: settings.message,
164
- });
148
+ await strapi
149
+ .plugin('email')
150
+ .service('email')
151
+ .send({
152
+ to: user.email,
153
+ from:
154
+ settings.from.email && settings.from.name
155
+ ? `${settings.from.name} <${settings.from.email}>`
156
+ : undefined,
157
+ replyTo: settings.response_email,
158
+ subject: settings.object,
159
+ text: settings.message,
160
+ html: settings.message,
161
+ });
165
162
  },
166
- };
163
+ });
@@ -0,0 +1,233 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const { filter, map, pipe, prop } = require('lodash/fp');
5
+
6
+ const { getService } = require('../utils');
7
+
8
+ const DEFAULT_PERMISSIONS = [
9
+ { action: 'plugin::users-permissions.auth.admincallback', roleType: 'public' },
10
+ { action: 'plugin::users-permissions.auth.adminregister', roleType: 'public' },
11
+ { action: 'plugin::users-permissions.auth.callback', roleType: 'public' },
12
+ { action: 'plugin::users-permissions.auth.connect', roleType: null },
13
+ { action: 'plugin::users-permissions.auth.forgotpassword', roleType: 'public' },
14
+ { action: 'plugin::users-permissions.auth.resetpassword', roleType: 'public' },
15
+ { action: 'plugin::users-permissions.auth.register', roleType: 'public' },
16
+ { action: 'plugin::users-permissions.auth.emailconfirmation', roleType: 'public' },
17
+ { action: 'plugin::users-permissions.user.me', roleType: null },
18
+ ];
19
+
20
+ const transformRoutePrefixFor = pluginName => route => {
21
+ const prefix = route.config && route.config.prefix;
22
+ const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;
23
+
24
+ return {
25
+ ...route,
26
+ path,
27
+ };
28
+ };
29
+
30
+ module.exports = ({ strapi }) => ({
31
+ getActions({ defaultEnable = false } = {}) {
32
+ const actionMap = {};
33
+
34
+ const isContentApi = action => {
35
+ if (!_.has(action, Symbol.for('__type__'))) {
36
+ return false;
37
+ }
38
+
39
+ return action[Symbol.for('__type__')].includes('content-api');
40
+ };
41
+
42
+ _.forEach(strapi.api, (api, apiName) => {
43
+ const controllers = _.reduce(
44
+ api.controllers,
45
+ (acc, controller, controllerName) => {
46
+ const contentApiActions = _.pickBy(controller, isContentApi);
47
+
48
+ if (_.isEmpty(contentApiActions)) {
49
+ return acc;
50
+ }
51
+
52
+ acc[controllerName] = _.mapValues(contentApiActions, () => {
53
+ return {
54
+ enabled: defaultEnable,
55
+ policy: '',
56
+ };
57
+ });
58
+
59
+ return acc;
60
+ },
61
+ {}
62
+ );
63
+
64
+ if (!_.isEmpty(controllers)) {
65
+ actionMap[`api::${apiName}`] = { controllers };
66
+ }
67
+ });
68
+
69
+ _.forEach(strapi.plugins, (plugin, pluginName) => {
70
+ const controllers = _.reduce(
71
+ plugin.controllers,
72
+ (acc, controller, controllerName) => {
73
+ const contentApiActions = _.pickBy(controller, isContentApi);
74
+
75
+ if (_.isEmpty(contentApiActions)) {
76
+ return acc;
77
+ }
78
+
79
+ acc[controllerName] = _.mapValues(contentApiActions, () => {
80
+ return {
81
+ enabled: defaultEnable,
82
+ policy: '',
83
+ };
84
+ });
85
+
86
+ return acc;
87
+ },
88
+ {}
89
+ );
90
+
91
+ if (!_.isEmpty(controllers)) {
92
+ actionMap[`plugin::${pluginName}`] = { controllers };
93
+ }
94
+ });
95
+
96
+ return actionMap;
97
+ },
98
+
99
+ async getRoutes() {
100
+ const routesMap = {};
101
+
102
+ _.forEach(strapi.api, (api, apiName) => {
103
+ const routes = _.flatMap(api.routes, route => {
104
+ if (_.has(route, 'routes')) {
105
+ return route.routes;
106
+ }
107
+
108
+ return route;
109
+ }).filter(route => route.info.type === 'content-api');
110
+
111
+ if (routes.length === 0) {
112
+ return;
113
+ }
114
+
115
+ routesMap[`api::${apiName}`] = routes.map(route => ({
116
+ ...route,
117
+ path: `/api${route.path}`,
118
+ }));
119
+ });
120
+
121
+ _.forEach(strapi.plugins, (plugin, pluginName) => {
122
+ const transformPrefix = transformRoutePrefixFor(pluginName);
123
+
124
+ const routes = _.flatMap(plugin.routes, route => {
125
+ if (_.has(route, 'routes')) {
126
+ return route.routes.map(transformPrefix);
127
+ }
128
+
129
+ return transformPrefix(route);
130
+ }).filter(route => route.info.type === 'content-api');
131
+
132
+ if (routes.length === 0) {
133
+ return;
134
+ }
135
+
136
+ routesMap[`plugin::${pluginName}`] = routes.map(route => ({
137
+ ...route,
138
+ path: `/api${route.path}`,
139
+ }));
140
+ });
141
+
142
+ return routesMap;
143
+ },
144
+
145
+ async syncPermissions() {
146
+ const roles = await strapi.query('plugin::users-permissions.role').findMany();
147
+ const dbPermissions = await strapi.query('plugin::users-permissions.permission').findMany();
148
+
149
+ const permissionsFoundInDB = _.uniq(_.map(dbPermissions, 'action'));
150
+
151
+ const appActions = _.flatMap(strapi.api, (api, apiName) => {
152
+ return _.flatMap(api.controllers, (controller, controllerName) => {
153
+ return _.keys(controller).map(actionName => {
154
+ return `api::${apiName}.${controllerName}.${actionName}`;
155
+ });
156
+ });
157
+ });
158
+
159
+ const pluginsActions = _.flatMap(strapi.plugins, (plugin, pluginName) => {
160
+ return _.flatMap(plugin.controllers, (controller, controllerName) => {
161
+ return _.keys(controller).map(actionName => {
162
+ return `plugin::${pluginName}.${controllerName}.${actionName}`;
163
+ });
164
+ });
165
+ });
166
+
167
+ const allActions = [...appActions, ...pluginsActions];
168
+
169
+ const toDelete = _.difference(permissionsFoundInDB, allActions);
170
+
171
+ await Promise.all(
172
+ toDelete.map(action => {
173
+ return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });
174
+ })
175
+ );
176
+
177
+ if (permissionsFoundInDB.length === 0) {
178
+ // create default permissions
179
+ for (const role of roles) {
180
+ const toCreate = pipe(
181
+ filter(({ roleType }) => roleType === role.type || roleType === null),
182
+ map(prop('action'))
183
+ )(DEFAULT_PERMISSIONS);
184
+
185
+ await Promise.all(
186
+ toCreate.map(action => {
187
+ return strapi.query('plugin::users-permissions.permission').create({
188
+ data: {
189
+ action,
190
+ role: role.id,
191
+ },
192
+ });
193
+ })
194
+ );
195
+ }
196
+ }
197
+ },
198
+
199
+ async initialize() {
200
+ const roleCount = await strapi.query('plugin::users-permissions.role').count();
201
+
202
+ if (roleCount === 0) {
203
+ await strapi.query('plugin::users-permissions.role').create({
204
+ data: {
205
+ name: 'Authenticated',
206
+ description: 'Default role given to authenticated user.',
207
+ type: 'authenticated',
208
+ },
209
+ });
210
+
211
+ await strapi.query('plugin::users-permissions.role').create({
212
+ data: {
213
+ name: 'Public',
214
+ description: 'Default role given to unauthenticated user.',
215
+ type: 'public',
216
+ },
217
+ });
218
+ }
219
+
220
+ return getService('users-permissions').syncPermissions();
221
+ },
222
+
223
+ async updateUserRole(user, role) {
224
+ return strapi
225
+ .query('plugin::users-permissions.user')
226
+ .update({ where: { id: user.id }, data: { role } });
227
+ },
228
+
229
+ template(layout, data) {
230
+ const compiledObject = _.template(layout);
231
+ return compiledObject(data);
232
+ },
233
+ });
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+
3
+ const { castArray, map } = require('lodash/fp');
4
+ const { ForbiddenError, UnauthorizedError } = require('@strapi/utils').errors;
5
+
6
+ const { getService } = require('../utils');
7
+
8
+ const getAdvancedSettings = () => {
9
+ return strapi.store({ type: 'plugin', name: 'users-permissions' }).get({ key: 'advanced' });
10
+ };
11
+
12
+ const authenticate = async ctx => {
13
+ try {
14
+ const token = await getService('jwt').getToken(ctx);
15
+
16
+ if (token) {
17
+ const { id } = token;
18
+
19
+ if (id === undefined) {
20
+ return { authenticated: false };
21
+ }
22
+
23
+ // fetch authenticated user
24
+ const user = await getService('user').fetchAuthenticatedUser(id);
25
+
26
+ if (!user) {
27
+ return { error: 'Invalid credentials' };
28
+ }
29
+
30
+ const advancedSettings = await getAdvancedSettings();
31
+
32
+ if (advancedSettings.email_confirmation && !user.confirmed) {
33
+ return { error: 'Invalid credentials' };
34
+ }
35
+
36
+ if (user.blocked) {
37
+ return { error: 'Invalid credentials' };
38
+ }
39
+
40
+ ctx.state.user = user;
41
+
42
+ return {
43
+ authenticated: true,
44
+ credentials: user,
45
+ };
46
+ }
47
+
48
+ const publicPermissions = await strapi.query('plugin::users-permissions.permission').findMany({
49
+ where: {
50
+ role: { type: 'public' },
51
+ },
52
+ });
53
+
54
+ if (publicPermissions.length === 0) {
55
+ return { authenticated: false };
56
+ }
57
+
58
+ return {
59
+ authenticated: true,
60
+ credentials: null,
61
+ };
62
+ } catch (err) {
63
+ return { authenticated: false };
64
+ }
65
+ };
66
+
67
+ const verify = async (auth, config) => {
68
+ const { credentials: user } = auth;
69
+
70
+ // public accesss
71
+ if (!user) {
72
+ // test against public role
73
+ const publicPermissions = await strapi.query('plugin::users-permissions.permission').findMany({
74
+ where: {
75
+ role: { type: 'public' },
76
+ },
77
+ });
78
+
79
+ const allowedActions = map('action', publicPermissions);
80
+
81
+ // A non authenticated user cannot access routes that do not have a scope
82
+ if (!config.scope) {
83
+ throw new UnauthorizedError();
84
+ }
85
+
86
+ const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
87
+
88
+ if (!isAllowed) {
89
+ throw new ForbiddenError();
90
+ }
91
+
92
+ return;
93
+ }
94
+
95
+ const permissions = await strapi.query('plugin::users-permissions.permission').findMany({
96
+ where: { role: user.role.id },
97
+ });
98
+
99
+ const allowedActions = map('action', permissions);
100
+
101
+ // An authenticated user can access non scoped routes
102
+ if (!config.scope) {
103
+ return;
104
+ }
105
+
106
+ const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
107
+
108
+ if (!isAllowed) {
109
+ throw new ForbiddenError();
110
+ }
111
+
112
+ // TODO: if we need to keep policies for u&p execution
113
+ // Execute the policies.
114
+ // if (permission.policy) {
115
+ // return await strapi.plugin('users-permissions').policy(permission.policy)(ctx, next);
116
+ // }
117
+ };
118
+
119
+ module.exports = {
120
+ name: 'users-permissions',
121
+ authenticate,
122
+ verify,
123
+ };
@@ -1,11 +1,16 @@
1
1
  import * as usersPermissions from '../services/users-permissions';
2
2
  import * as user from '../services/user';
3
+ import * as role from '../services/role';
3
4
  import * as jwt from '../services/jwt';
5
+ import * as providers from '../services/providers';
6
+
4
7
 
5
8
  type S = {
6
9
  ['users-permissions']: typeof usersPermissions;
10
+ ['role']: typeof role;
7
11
  user: typeof user;
8
12
  jwt: typeof jwt;
13
+ providers: typeof providers;
9
14
  };
10
15
 
11
- export function getService<T extends keyof S>(name: T): S[T];
16
+ export function getService<T extends keyof S>(name: T): ReturnType<S[T]>;
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const getService = name => {
4
+ return strapi.plugin('users-permissions').service(name);
5
+ };
6
+
7
+ module.exports = {
8
+ getService,
9
+ };