@strapi/plugin-users-permissions 4.0.0-next.1 → 4.0.0-next.13
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.
- package/admin/src/index.js +31 -28
- package/admin/src/pages/AdvancedSettings/index.js +14 -2
- package/admin/src/pages/AdvancedSettings/utils/form.js +2 -2
- package/admin/src/pages/EmailTemplates/index.js +8 -1
- package/admin/src/pages/Providers/index.js +8 -1
- package/admin/src/pages/Roles/CreatePage/index.js +1 -1
- package/admin/src/pages/Roles/EditPage/index.js +2 -2
- package/admin/src/pages/Roles/ListPage/index.js +1 -1
- package/admin/src/pages/Roles/index.js +14 -8
- package/admin/src/permissions.js +12 -14
- package/admin/src/translations/en.json +4 -0
- package/admin/src/translations/zh-Hans.json +26 -7
- package/documentation/1.0.0/overrides/users-permissions-Role.json +6 -6
- package/package.json +8 -6
- package/{config/functions/bootstrap.js → server/bootstrap/index.js} +9 -18
- package/{config → server/bootstrap}/users-permissions-actions.js +0 -0
- package/server/config.js +23 -0
- package/server/content-types/index.js +11 -0
- package/server/content-types/permission/index.js +31 -0
- package/server/content-types/role/index.js +48 -0
- package/server/content-types/user/index.js +72 -0
- package/{models/User.config.js → server/content-types/user/schema-config.js} +0 -0
- package/{controllers → server/controllers}/auth.js +63 -77
- package/server/controllers/index.js +15 -0
- package/server/controllers/permissions.js +26 -0
- package/server/controllers/role.js +77 -0
- package/server/controllers/settings.js +84 -0
- package/{controllers → server/controllers}/user/admin.js +26 -42
- package/{controllers → server/controllers}/user/api.js +11 -27
- package/{controllers → server/controllers}/user.js +2 -18
- package/{controllers → server/controllers}/validation/email-template.js +0 -0
- package/server/index.js +21 -0
- package/server/policies/index.js +7 -0
- package/{config → server}/policies/rateLimit.js +4 -8
- package/server/register.js +7 -0
- package/server/routes/admin/index.js +10 -0
- package/server/routes/admin/permissions.js +20 -0
- package/server/routes/admin/role.js +79 -0
- package/server/routes/admin/settings.js +95 -0
- package/server/routes/content-api/auth.js +73 -0
- package/server/routes/content-api/index.js +11 -0
- package/server/routes/content-api/permissions.js +9 -0
- package/server/routes/content-api/role.js +29 -0
- package/server/routes/content-api/user.js +61 -0
- package/server/routes/index.js +6 -0
- package/{config → server}/schema.graphql.js +96 -63
- package/server/services/index.js +15 -0
- package/{services → server/services}/jwt.js +12 -14
- package/server/services/providers.js +592 -0
- package/server/services/role.js +182 -0
- package/{services → server/services}/user.js +31 -34
- package/server/services/users-permissions.js +222 -0
- package/server/strategies/users-permissions.js +122 -0
- package/{utils → server/utils}/index.d.ts +6 -1
- package/server/utils/index.js +9 -0
- package/strapi-server.js +3 -0
- package/config/layout.js +0 -10
- package/config/policies/isAuthenticated.js +0 -9
- package/config/policies/permissions.js +0 -94
- package/config/request.json +0 -6
- package/config/routes.json +0 -381
- package/config/security.json +0 -5
- package/controllers/users-permissions.js +0 -271
- package/middlewares/users-permissions/defaults.json +0 -5
- package/middlewares/users-permissions/index.js +0 -40
- package/models/Permission.js +0 -7
- package/models/Permission.settings.json +0 -45
- package/models/Role.js +0 -7
- package/models/Role.settings.json +0 -43
- package/models/User.js +0 -7
- package/models/User.settings.json +0 -63
- package/services/providers.js +0 -598
- package/services/users-permissions.js +0 -430
- package/utils/index.js +0 -11
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { getService } = require('../utils');
|
|
5
|
+
|
|
6
|
+
module.exports = ({ strapi }) => ({
|
|
7
|
+
async createRole(params) {
|
|
8
|
+
if (!params.type) {
|
|
9
|
+
params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const role = await strapi
|
|
13
|
+
.query('plugin::users-permissions.role')
|
|
14
|
+
.create({ data: _.omit(params, ['users', 'permissions']) });
|
|
15
|
+
|
|
16
|
+
const createPromises = _.flatMap(params.permissions, (type, typeName) => {
|
|
17
|
+
return _.flatMap(type.controllers, (controller, controllerName) => {
|
|
18
|
+
return _.reduce(
|
|
19
|
+
controller,
|
|
20
|
+
(acc, action, actionName) => {
|
|
21
|
+
const { enabled /* policy */ } = action;
|
|
22
|
+
|
|
23
|
+
if (enabled) {
|
|
24
|
+
const actionID = `${typeName}.${controllerName}.${actionName}`;
|
|
25
|
+
|
|
26
|
+
acc.push(
|
|
27
|
+
strapi
|
|
28
|
+
.query('plugin::users-permissions.permission')
|
|
29
|
+
.create({ data: { action: actionID, role: role.id } })
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return acc;
|
|
34
|
+
},
|
|
35
|
+
[]
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await Promise.all(createPromises);
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
async getRole(roleID, plugins) {
|
|
44
|
+
const role = await strapi
|
|
45
|
+
.query('plugin::users-permissions.role')
|
|
46
|
+
.findOne({ where: { id: roleID }, populate: ['permissions'] });
|
|
47
|
+
|
|
48
|
+
if (!role) {
|
|
49
|
+
throw new Error('Role not found');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const allActions = getService('users-permissions').getActions();
|
|
53
|
+
|
|
54
|
+
// Group by `type`.
|
|
55
|
+
role.permissions.forEach(permission => {
|
|
56
|
+
const [type, controller, action] = permission.action.split('.');
|
|
57
|
+
|
|
58
|
+
_.set(allActions, `${type}.controllers.${controller}.${action}`, {
|
|
59
|
+
enabled: true,
|
|
60
|
+
policy: '',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (permission.action.startsWith('plugin')) {
|
|
64
|
+
const [, pluginName] = type.split('::');
|
|
65
|
+
|
|
66
|
+
allActions[type].information = plugins.find(plugin => plugin.id === pluginName) || {};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
...role,
|
|
72
|
+
permissions: allActions,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async getRoles() {
|
|
77
|
+
const roles = await strapi.query('plugin::users-permissions.role').findMany({ sort: ['name'] });
|
|
78
|
+
|
|
79
|
+
for (const role of roles) {
|
|
80
|
+
roles.nb_users = await strapi
|
|
81
|
+
.query('plugin::users-permissions.user')
|
|
82
|
+
.count({ where: { role: { id: role.id } } });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return roles;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async updateRole(roleID, data) {
|
|
89
|
+
const role = await strapi
|
|
90
|
+
.query('plugin::users-permissions.role')
|
|
91
|
+
.findOne({ where: { id: roleID }, populate: ['permissions'] });
|
|
92
|
+
|
|
93
|
+
if (!role) {
|
|
94
|
+
throw new Error('Role not found');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
await strapi.query('plugin::users-permissions.role').update({
|
|
98
|
+
where: { id: roleID },
|
|
99
|
+
data: _.pick(data, ['name', 'description']),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const { permissions } = data;
|
|
103
|
+
|
|
104
|
+
const newActions = _.flatMap(permissions, (type, typeName) => {
|
|
105
|
+
return _.flatMap(type.controllers, (controller, controllerName) => {
|
|
106
|
+
return _.reduce(
|
|
107
|
+
controller,
|
|
108
|
+
(acc, action, actionName) => {
|
|
109
|
+
const { enabled /* policy */ } = action;
|
|
110
|
+
|
|
111
|
+
if (enabled) {
|
|
112
|
+
acc.push(`${typeName}.${controllerName}.${actionName}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return acc;
|
|
116
|
+
},
|
|
117
|
+
[]
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const oldActions = role.permissions.map(({ action }) => action);
|
|
123
|
+
|
|
124
|
+
const toDelete = role.permissions.reduce((acc, permission) => {
|
|
125
|
+
if (!newActions.includes(permission.action)) {
|
|
126
|
+
acc.push(permission);
|
|
127
|
+
}
|
|
128
|
+
return acc;
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
const toCreate = newActions
|
|
132
|
+
.filter(action => !oldActions.includes(action))
|
|
133
|
+
.map(action => ({ action, role: role.id }));
|
|
134
|
+
|
|
135
|
+
await Promise.all(
|
|
136
|
+
toDelete.map(permission =>
|
|
137
|
+
strapi
|
|
138
|
+
.query('plugin::users-permissions.permission')
|
|
139
|
+
.delete({ where: { id: permission.id } })
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await Promise.all(
|
|
144
|
+
toCreate.map(permissionInfo =>
|
|
145
|
+
strapi.query('plugin::users-permissions.permission').create({ data: permissionInfo })
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
async deleteRole(roleID, publicRoleID) {
|
|
151
|
+
const role = await strapi
|
|
152
|
+
.query('plugin::users-permissions.role')
|
|
153
|
+
.findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
|
|
154
|
+
|
|
155
|
+
if (!role) {
|
|
156
|
+
throw new Error('Role not found');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Move users to guest role.
|
|
160
|
+
await Promise.all(
|
|
161
|
+
role.users.map(user => {
|
|
162
|
+
return strapi.query('plugin::users-permissions.user').update({
|
|
163
|
+
where: { id: user.id },
|
|
164
|
+
data: { role: publicRoleID },
|
|
165
|
+
});
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Remove permissions related to this role.
|
|
170
|
+
// TODO: use delete many
|
|
171
|
+
await Promise.all(
|
|
172
|
+
role.permissions.map(permission => {
|
|
173
|
+
return strapi.query('plugin::users-permissions.permission').delete({
|
|
174
|
+
where: { id: permission.id },
|
|
175
|
+
});
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Delete the role.
|
|
180
|
+
await strapi.query('plugin::users-permissions.role').delete({ where: { id: roleID } });
|
|
181
|
+
},
|
|
182
|
+
});
|
|
@@ -12,7 +12,7 @@ const bcrypt = require('bcryptjs');
|
|
|
12
12
|
const { sanitizeEntity, getAbsoluteServerUrl } = 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('
|
|
23
|
+
return strapi.query('plugin::users-permissions.user').count({ where: params });
|
|
24
24
|
},
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -35,12 +35,12 @@ module.exports = {
|
|
|
35
35
|
*/
|
|
36
36
|
async add(values) {
|
|
37
37
|
if (values.password) {
|
|
38
|
-
values.password = await
|
|
39
|
-
values
|
|
40
|
-
);
|
|
38
|
+
values.password = await getService('user').hashPassword(values);
|
|
41
39
|
}
|
|
42
40
|
|
|
43
|
-
return strapi
|
|
41
|
+
return strapi
|
|
42
|
+
.query('plugin::users-permissions.user')
|
|
43
|
+
.create({ data: values, populate: ['role'] });
|
|
44
44
|
},
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -52,7 +52,9 @@ module.exports = {
|
|
|
52
52
|
values.password = await getService('user').hashPassword(values);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
return strapi
|
|
55
|
+
return strapi
|
|
56
|
+
.query('plugin::users-permissions.user')
|
|
57
|
+
.update({ where: params, data: values, populate: ['role'] });
|
|
56
58
|
},
|
|
57
59
|
|
|
58
60
|
/**
|
|
@@ -60,7 +62,7 @@ module.exports = {
|
|
|
60
62
|
* @return {Promise}
|
|
61
63
|
*/
|
|
62
64
|
fetch(params, populate) {
|
|
63
|
-
return strapi.query('
|
|
65
|
+
return strapi.query('plugin::users-permissions.user').findOne({ where: params, populate });
|
|
64
66
|
},
|
|
65
67
|
|
|
66
68
|
/**
|
|
@@ -69,7 +71,7 @@ module.exports = {
|
|
|
69
71
|
*/
|
|
70
72
|
fetchAuthenticatedUser(id) {
|
|
71
73
|
return strapi
|
|
72
|
-
.query('
|
|
74
|
+
.query('plugin::users-permissions.user')
|
|
73
75
|
.findOne({ where: { id }, populate: ['role'] });
|
|
74
76
|
},
|
|
75
77
|
|
|
@@ -78,7 +80,7 @@ module.exports = {
|
|
|
78
80
|
* @return {Promise}
|
|
79
81
|
*/
|
|
80
82
|
fetchAll(params, populate) {
|
|
81
|
-
return strapi.query('
|
|
83
|
+
return strapi.query('plugin::users-permissions.user').findMany({ where: params, populate });
|
|
82
84
|
},
|
|
83
85
|
|
|
84
86
|
hashPassword(user = {}) {
|
|
@@ -109,11 +111,7 @@ module.exports = {
|
|
|
109
111
|
* @return {Promise}
|
|
110
112
|
*/
|
|
111
113
|
async remove(params) {
|
|
112
|
-
return strapi.query('
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
async removeAll(params) {
|
|
116
|
-
return strapi.query('plugins::users-permissions.user').delete({ where: params });
|
|
114
|
+
return strapi.query('plugin::users-permissions.user').delete({ where: params });
|
|
117
115
|
},
|
|
118
116
|
|
|
119
117
|
validatePassword(password, hash) {
|
|
@@ -121,19 +119,15 @@ module.exports = {
|
|
|
121
119
|
},
|
|
122
120
|
|
|
123
121
|
async sendConfirmationEmail(user) {
|
|
124
|
-
const userPermissionService =
|
|
125
|
-
const pluginStore = await strapi.store({
|
|
126
|
-
environment: '',
|
|
127
|
-
type: 'plugin',
|
|
128
|
-
name: 'users-permissions',
|
|
129
|
-
});
|
|
122
|
+
const userPermissionService = getService('users-permissions');
|
|
123
|
+
const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
|
|
130
124
|
|
|
131
125
|
const settings = await pluginStore
|
|
132
126
|
.get({ key: 'email' })
|
|
133
127
|
.then(storeEmail => storeEmail['email_confirmation'].options);
|
|
134
128
|
|
|
135
129
|
const userInfo = sanitizeEntity(user, {
|
|
136
|
-
model: strapi.getModel('
|
|
130
|
+
model: strapi.getModel('plugin::users-permissions.user'),
|
|
137
131
|
});
|
|
138
132
|
|
|
139
133
|
const confirmationToken = crypto.randomBytes(20).toString('hex');
|
|
@@ -149,16 +143,19 @@ module.exports = {
|
|
|
149
143
|
settings.object = await userPermissionService.template(settings.object, { USER: userInfo });
|
|
150
144
|
|
|
151
145
|
// Send an email to the user.
|
|
152
|
-
await strapi
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
146
|
+
await strapi
|
|
147
|
+
.plugin('email')
|
|
148
|
+
.service('email')
|
|
149
|
+
.send({
|
|
150
|
+
to: user.email,
|
|
151
|
+
from:
|
|
152
|
+
settings.from.email && settings.from.name
|
|
153
|
+
? `${settings.from.name} <${settings.from.email}>`
|
|
154
|
+
: undefined,
|
|
155
|
+
replyTo: settings.response_email,
|
|
156
|
+
subject: settings.object,
|
|
157
|
+
text: settings.message,
|
|
158
|
+
html: settings.message,
|
|
159
|
+
});
|
|
163
160
|
},
|
|
164
|
-
};
|
|
161
|
+
});
|
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
getPlugins(lang = 'en') {
|
|
32
|
+
const request = require('request');
|
|
33
|
+
return new Promise(resolve => {
|
|
34
|
+
request(
|
|
35
|
+
{
|
|
36
|
+
uri: `https://marketplace.strapi.io/plugins?lang=${lang}`,
|
|
37
|
+
json: true,
|
|
38
|
+
timeout: 3000,
|
|
39
|
+
headers: {
|
|
40
|
+
'cache-control': 'max-age=3600',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
(err, response, body) => {
|
|
44
|
+
if (err || response.statusCode !== 200) {
|
|
45
|
+
return resolve([]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
resolve(body);
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// TODO: Filter on content-api only
|
|
55
|
+
getActions({ defaultEnable = false } = {}) {
|
|
56
|
+
const actionMap = {};
|
|
57
|
+
|
|
58
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
59
|
+
const controllers = _.mapValues(api.controllers, controller => {
|
|
60
|
+
return _.mapValues(controller, () => {
|
|
61
|
+
return {
|
|
62
|
+
enabled: defaultEnable,
|
|
63
|
+
policy: '',
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
actionMap[`api::${apiName}`] = { controllers };
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
72
|
+
const controllers = _.mapValues(plugin.controllers, controller => {
|
|
73
|
+
return _.mapValues(controller, () => {
|
|
74
|
+
return {
|
|
75
|
+
enabled: defaultEnable,
|
|
76
|
+
policy: '',
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
actionMap[`plugin::${pluginName}`] = { controllers };
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return actionMap;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// TODO: Filter on content-api only
|
|
88
|
+
async getRoutes() {
|
|
89
|
+
const routesMap = {};
|
|
90
|
+
|
|
91
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
92
|
+
const routes = _.flatMap(api.routes, route => {
|
|
93
|
+
if (_.has(route, 'routes')) {
|
|
94
|
+
return route.routes;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return route;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (routes.length === 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
routesMap[`api::${apiName}`] = routes.map(route => ({
|
|
105
|
+
...route,
|
|
106
|
+
path: `/api${route.path}`,
|
|
107
|
+
}));
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
111
|
+
const transformPrefix = transformRoutePrefixFor(pluginName);
|
|
112
|
+
|
|
113
|
+
const routes = _.flatMap(plugin.routes, route => {
|
|
114
|
+
if (_.has(route, 'routes')) {
|
|
115
|
+
return route.routes.map(transformPrefix);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return transformPrefix(route);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (routes.length === 0) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
routesMap[`plugin::${pluginName}`] = routes.map(route => ({
|
|
126
|
+
...route,
|
|
127
|
+
path: `/api${route.path}`,
|
|
128
|
+
}));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return routesMap;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async syncPermissions() {
|
|
135
|
+
const roles = await strapi.query('plugin::users-permissions.role').findMany();
|
|
136
|
+
const dbPermissions = await strapi.query('plugin::users-permissions.permission').findMany();
|
|
137
|
+
|
|
138
|
+
const permissionsFoundInDB = _.uniq(_.map(dbPermissions, 'action'));
|
|
139
|
+
|
|
140
|
+
const appActions = _.flatMap(strapi.api, (api, apiName) => {
|
|
141
|
+
return _.flatMap(api.controllers, (controller, controllerName) => {
|
|
142
|
+
return _.keys(controller).map(actionName => {
|
|
143
|
+
return `api::${apiName}.${controllerName}.${actionName}`;
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const pluginsActions = _.flatMap(strapi.plugins, (plugin, pluginName) => {
|
|
149
|
+
return _.flatMap(plugin.controllers, (controller, controllerName) => {
|
|
150
|
+
return _.keys(controller).map(actionName => {
|
|
151
|
+
return `plugin::${pluginName}.${controllerName}.${actionName}`;
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const allActions = [...appActions, ...pluginsActions];
|
|
157
|
+
|
|
158
|
+
const toDelete = _.difference(permissionsFoundInDB, allActions);
|
|
159
|
+
|
|
160
|
+
await Promise.all(
|
|
161
|
+
toDelete.map(action => {
|
|
162
|
+
return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (permissionsFoundInDB.length === 0) {
|
|
167
|
+
// create default permissions
|
|
168
|
+
for (const role of roles) {
|
|
169
|
+
const toCreate = pipe(
|
|
170
|
+
filter(({ roleType }) => roleType === role.type || roleType === null),
|
|
171
|
+
map(prop('action'))
|
|
172
|
+
)(DEFAULT_PERMISSIONS);
|
|
173
|
+
|
|
174
|
+
await Promise.all(
|
|
175
|
+
toCreate.map(action => {
|
|
176
|
+
return strapi.query('plugin::users-permissions.permission').create({
|
|
177
|
+
data: {
|
|
178
|
+
action,
|
|
179
|
+
role: role.id,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
async initialize() {
|
|
189
|
+
const roleCount = await strapi.query('plugin::users-permissions.role').count();
|
|
190
|
+
|
|
191
|
+
if (roleCount === 0) {
|
|
192
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
193
|
+
data: {
|
|
194
|
+
name: 'Authenticated',
|
|
195
|
+
description: 'Default role given to authenticated user.',
|
|
196
|
+
type: 'authenticated',
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
201
|
+
data: {
|
|
202
|
+
name: 'Public',
|
|
203
|
+
description: 'Default role given to unauthenticated user.',
|
|
204
|
+
type: 'public',
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return getService('users-permissions').syncPermissions();
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
async updateUserRole(user, role) {
|
|
213
|
+
return strapi
|
|
214
|
+
.query('plugin::users-permissions.user')
|
|
215
|
+
.update({ where: { id: user.id }, data: { role } });
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
template(layout, data) {
|
|
219
|
+
const compiledObject = _.template(layout);
|
|
220
|
+
return compiledObject(data);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { castArray, map } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { getService } = require('../utils');
|
|
6
|
+
|
|
7
|
+
const getAdvancedSettings = () => {
|
|
8
|
+
return strapi.store({ type: 'plugin', name: 'users-permissions' }).get({ key: 'advanced' });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const authenticate = async ctx => {
|
|
12
|
+
if (ctx.request && ctx.request.header && ctx.request.header.authorization) {
|
|
13
|
+
try {
|
|
14
|
+
const { id } = await getService('jwt').getToken(ctx);
|
|
15
|
+
|
|
16
|
+
if (id === undefined) {
|
|
17
|
+
return { authenticated: false };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// fetch authenticated user
|
|
21
|
+
const user = await getService('user').fetchAuthenticatedUser(id);
|
|
22
|
+
|
|
23
|
+
if (!user) {
|
|
24
|
+
return { error: 'Invalid credentials' };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const advancedSettings = await getAdvancedSettings();
|
|
28
|
+
|
|
29
|
+
if (advancedSettings.email_confirmation && !user.confirmed) {
|
|
30
|
+
return { error: 'Invalid credentials' };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (user.blocked) {
|
|
34
|
+
return { error: 'Invalid credentials' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ctx.state.user = user;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
authenticated: true,
|
|
41
|
+
credentials: user,
|
|
42
|
+
};
|
|
43
|
+
} catch (err) {
|
|
44
|
+
return { authenticated: false };
|
|
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
|
+
};
|
|
63
|
+
|
|
64
|
+
const verify = async (auth, config) => {
|
|
65
|
+
const { errors } = strapi.container.get('auth');
|
|
66
|
+
|
|
67
|
+
const { credentials: user } = auth;
|
|
68
|
+
|
|
69
|
+
// public accesss
|
|
70
|
+
if (!user) {
|
|
71
|
+
// test against public role
|
|
72
|
+
const publicPermissions = await strapi.query('plugin::users-permissions.permission').findMany({
|
|
73
|
+
where: {
|
|
74
|
+
role: { type: 'public' },
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const allowedActions = map('action', publicPermissions);
|
|
79
|
+
|
|
80
|
+
// A non authenticated user cannot access routes that do not have a scope
|
|
81
|
+
if (!config.scope) {
|
|
82
|
+
throw new errors.UnauthorizedError();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
|
|
86
|
+
|
|
87
|
+
if (!isAllowed) {
|
|
88
|
+
throw new errors.ForbiddenError();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const permissions = await strapi.query('plugin::users-permissions.permission').findMany({
|
|
95
|
+
where: { role: user.role.id },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const allowedActions = map('action', permissions);
|
|
99
|
+
|
|
100
|
+
// An authenticated user can access non scoped routes
|
|
101
|
+
if (!config.scope) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
|
|
106
|
+
|
|
107
|
+
if (!isAllowed) {
|
|
108
|
+
throw new errors.ForbiddenError();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// TODO: if we need to keep policies for u&p execution
|
|
112
|
+
// Execute the policies.
|
|
113
|
+
// if (permission.policy) {
|
|
114
|
+
// return await strapi.plugin('users-permissions').policy(permission.policy)(ctx, next);
|
|
115
|
+
// }
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
module.exports = {
|
|
119
|
+
name: 'users-permissions',
|
|
120
|
+
authenticate,
|
|
121
|
+
verify,
|
|
122
|
+
};
|
|
@@ -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]>;
|
package/strapi-server.js
ADDED