@strapi/plugin-users-permissions 4.2.0-beta.0 → 4.2.0-beta.3
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/components/FormModal/index.js +1 -1
- package/admin/src/index.js +1 -1
- package/admin/src/pages/AdvancedSettings/index.js +2 -2
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +2 -2
- package/admin/src/pages/Providers/index.js +4 -4
- package/admin/src/pages/Roles/CreatePage/index.js +3 -3
- package/admin/src/pages/Roles/EditPage/index.js +15 -15
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +2 -3
- package/admin/src/pages/Roles/ListPage/index.js +6 -6
- package/admin/src/translations/ar.json +0 -1
- package/admin/src/translations/cs.json +0 -1
- package/admin/src/translations/de.json +0 -2
- package/admin/src/translations/dk.json +0 -11
- package/admin/src/translations/en.json +0 -11
- package/admin/src/translations/es.json +0 -11
- package/admin/src/translations/fr.json +0 -1
- package/admin/src/translations/id.json +0 -2
- package/admin/src/translations/it.json +0 -2
- package/admin/src/translations/ja.json +0 -1
- package/admin/src/translations/ko.json +0 -11
- package/admin/src/translations/ms.json +0 -1
- package/admin/src/translations/nl.json +0 -1
- package/admin/src/translations/pl.json +0 -1
- package/admin/src/translations/pt-BR.json +0 -1
- package/admin/src/translations/pt.json +0 -1
- package/admin/src/translations/ru.json +0 -2
- package/admin/src/translations/sk.json +0 -1
- package/admin/src/translations/sv.json +0 -2
- package/admin/src/translations/th.json +0 -2
- package/admin/src/translations/tr.json +0 -1
- package/admin/src/translations/uk.json +0 -1
- package/admin/src/translations/vi.json +0 -1
- package/admin/src/translations/zh-Hans.json +0 -3
- package/admin/src/translations/zh.json +0 -1
- package/package.json +6 -8
- package/server/bootstrap/index.js +13 -4
- package/server/controllers/auth.js +11 -16
- package/server/controllers/role.js +4 -4
- package/server/controllers/settings.js +1 -1
- package/server/controllers/user.js +10 -5
- package/server/controllers/validation/email-template.js +10 -1
- package/server/graphql/mutations/auth/email-confirmation.js +1 -1
- package/server/graphql/mutations/crud/user/delete-user.js +1 -1
- package/server/graphql/resolvers-configs.js +4 -4
- package/server/register.js +2 -0
- package/server/routes/admin/role.js +2 -2
- package/server/routes/content-api/role.js +2 -2
- package/server/services/providers-list.js +152 -348
- package/server/services/providers.js +58 -69
- package/server/services/role.js +2 -2
- package/server/services/user.js +7 -5
- package/server/utils/index.js +3 -0
- package/server/utils/sanitize/index.js +9 -0
- package/server/utils/sanitize/sanitizers.js +19 -0
- package/server/utils/sanitize/visitors/index.js +5 -0
- package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +11 -0
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"HeaderNav.link.advancedSettings": "進階設定",
|
|
14
14
|
"HeaderNav.link.emailTemplates": "郵件範本",
|
|
15
15
|
"HeaderNav.link.providers": "驗證方式",
|
|
16
|
-
"HeaderNav.link.roles": "身份",
|
|
17
16
|
"Plugin.permissions.plugins.description": "為 {name} 擴充功能定義所有可用的操作",
|
|
18
17
|
"Plugins.header.description": "只有綁定路徑的操作會顯示在下方",
|
|
19
18
|
"Plugins.header.title": "權限",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-users-permissions",
|
|
3
|
-
"version": "4.2.0-beta.
|
|
3
|
+
"version": "4.2.0-beta.3",
|
|
4
4
|
"description": "Protect your API with a full-authentication process based on JWT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,15 +27,14 @@
|
|
|
27
27
|
"test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@
|
|
31
|
-
"@strapi/
|
|
32
|
-
"@strapi/utils": "4.2.0-beta.0",
|
|
30
|
+
"@strapi/helper-plugin": "4.2.0-beta.3",
|
|
31
|
+
"@strapi/utils": "4.2.0-beta.3",
|
|
33
32
|
"bcryptjs": "2.4.3",
|
|
34
33
|
"grant-koa": "5.4.8",
|
|
35
34
|
"jsonwebtoken": "^8.1.0",
|
|
36
35
|
"koa2-ratelimit": "^0.9.0",
|
|
37
36
|
"lodash": "4.17.21",
|
|
38
|
-
"purest": "
|
|
37
|
+
"purest": "4.0.2",
|
|
39
38
|
"react": "^17.0.2",
|
|
40
39
|
"react-dom": "^17.0.2",
|
|
41
40
|
"react-intl": "5.20.2",
|
|
@@ -44,8 +43,7 @@
|
|
|
44
43
|
"react-router-dom": "5.2.0",
|
|
45
44
|
"redux-saga": "^0.16.0",
|
|
46
45
|
"request": "^2.83.0",
|
|
47
|
-
"url-join": "4.0.1"
|
|
48
|
-
"uuid": "^3.1.0"
|
|
46
|
+
"url-join": "4.0.1"
|
|
49
47
|
},
|
|
50
48
|
"devDependencies": {
|
|
51
49
|
"koa": "^2.13.1"
|
|
@@ -61,5 +59,5 @@
|
|
|
61
59
|
"required": true,
|
|
62
60
|
"kind": "plugin"
|
|
63
61
|
},
|
|
64
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "c4addbad6ecbc8ef7633bbba3806f3b0a2ae5f49"
|
|
65
63
|
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* This gives you an opportunity to set up your data model,
|
|
8
8
|
* run jobs, or perform some special logic.
|
|
9
9
|
*/
|
|
10
|
+
const crypto = require('crypto');
|
|
10
11
|
const _ = require('lodash');
|
|
11
12
|
const urljoin = require('url-join');
|
|
12
|
-
const uuid = require('uuid/v4');
|
|
13
13
|
const { getService } = require('../utils');
|
|
14
14
|
const getGrantConfig = require('./grant-config');
|
|
15
15
|
|
|
@@ -29,13 +29,22 @@ module.exports = async ({ strapi }) => {
|
|
|
29
29
|
await getService('users-permissions').initialize();
|
|
30
30
|
|
|
31
31
|
if (!strapi.config.get('plugin.users-permissions.jwtSecret')) {
|
|
32
|
-
|
|
32
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Missing jwtSecret. Please, set configuration variable "jwtSecret" for the users-permissions plugin in config/plugins.js (ex: you can generate one using Node with \`crypto.randomBytes(16).toString('base64')\`).
|
|
35
|
+
For security reasons, prefer storing the secret in an environment variable and read it in config/plugins.js. See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const jwtSecret = crypto.randomBytes(16).toString('base64');
|
|
40
|
+
|
|
33
41
|
strapi.config.set('plugin.users-permissions.jwtSecret', jwtSecret);
|
|
34
42
|
|
|
35
43
|
if (!process.env.JWT_SECRET) {
|
|
36
|
-
|
|
44
|
+
const envPath = process.env.ENV_PATH || '.env';
|
|
45
|
+
strapi.fs.appendFile(envPath, `JWT_SECRET=${jwtSecret}\n`);
|
|
37
46
|
strapi.log.info(
|
|
38
|
-
|
|
47
|
+
`The Users & Permissions plugin automatically generated a jwt secret and stored it in ${envPath} under the name JWT_SECRET.`
|
|
39
48
|
);
|
|
40
49
|
}
|
|
41
50
|
}
|
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
validateSendEmailConfirmationBody,
|
|
18
18
|
} = require('./validation/auth');
|
|
19
19
|
|
|
20
|
-
const { sanitize } = utils;
|
|
20
|
+
const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = utils;
|
|
21
21
|
const { ApplicationError, ValidationError } = utils.errors;
|
|
22
22
|
|
|
23
23
|
const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
@@ -34,7 +34,7 @@ module.exports = {
|
|
|
34
34
|
const provider = ctx.params.provider || 'local';
|
|
35
35
|
const params = ctx.request.body;
|
|
36
36
|
|
|
37
|
-
const store =
|
|
37
|
+
const store = strapi.store({ type: 'plugin', name: 'users-permissions' });
|
|
38
38
|
|
|
39
39
|
if (provider === 'local') {
|
|
40
40
|
if (!_.get(await store.get({ key: 'grant' }), 'email.enabled')) {
|
|
@@ -101,22 +101,15 @@ module.exports = {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Connect the user with the third-party provider.
|
|
104
|
-
let user;
|
|
105
|
-
let error;
|
|
106
104
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
const user = await getService('providers').connect(provider, ctx.query);
|
|
106
|
+
ctx.send({
|
|
107
|
+
jwt: getService('jwt').issue({ id: user.id }),
|
|
108
|
+
user: await sanitizeUser(user, ctx),
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
113
111
|
throw new ApplicationError(error.message);
|
|
114
112
|
}
|
|
115
|
-
|
|
116
|
-
ctx.send({
|
|
117
|
-
jwt: getService('jwt').issue({ id: user.id }),
|
|
118
|
-
user: await sanitizeUser(user, ctx),
|
|
119
|
-
});
|
|
120
113
|
}
|
|
121
114
|
},
|
|
122
115
|
|
|
@@ -243,6 +236,8 @@ module.exports = {
|
|
|
243
236
|
|
|
244
237
|
settings.message = await getService('users-permissions').template(settings.message, {
|
|
245
238
|
URL: advanced.email_reset_password,
|
|
239
|
+
SERVER_URL: getAbsoluteServerUrl(strapi.config),
|
|
240
|
+
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
|
|
246
241
|
USER: userInfo,
|
|
247
242
|
TOKEN: resetPasswordToken,
|
|
248
243
|
});
|
|
@@ -383,7 +378,7 @@ module.exports = {
|
|
|
383
378
|
throw new ValidationError('token.invalid');
|
|
384
379
|
}
|
|
385
380
|
|
|
386
|
-
const user = await userService.
|
|
381
|
+
const [user] = await userService.fetchAll({ filters: { confirmationToken } });
|
|
387
382
|
|
|
388
383
|
if (!user) {
|
|
389
384
|
throw new ValidationError('token.invalid');
|
|
@@ -21,10 +21,10 @@ module.exports = {
|
|
|
21
21
|
ctx.send({ ok: true });
|
|
22
22
|
},
|
|
23
23
|
|
|
24
|
-
async
|
|
24
|
+
async findOne(ctx) {
|
|
25
25
|
const { id } = ctx.params;
|
|
26
26
|
|
|
27
|
-
const role = await getService('role').
|
|
27
|
+
const role = await getService('role').findOne(id);
|
|
28
28
|
|
|
29
29
|
if (!role) {
|
|
30
30
|
return ctx.notFound();
|
|
@@ -33,8 +33,8 @@ module.exports = {
|
|
|
33
33
|
ctx.send({ role });
|
|
34
34
|
},
|
|
35
35
|
|
|
36
|
-
async
|
|
37
|
-
const roles = await getService('role').
|
|
36
|
+
async find(ctx) {
|
|
37
|
+
const roles = await getService('role').find();
|
|
38
38
|
|
|
39
39
|
ctx.send({ roles });
|
|
40
40
|
},
|
|
@@ -12,7 +12,7 @@ const { getService } = require('../utils');
|
|
|
12
12
|
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
13
13
|
|
|
14
14
|
const { sanitize } = utils;
|
|
15
|
-
const { ApplicationError, ValidationError } = utils.errors;
|
|
15
|
+
const { ApplicationError, ValidationError, NotFoundError } = utils.errors;
|
|
16
16
|
|
|
17
17
|
const sanitizeOutput = (user, ctx) => {
|
|
18
18
|
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
@@ -90,7 +90,10 @@ module.exports = {
|
|
|
90
90
|
const { id } = ctx.params;
|
|
91
91
|
const { email, username, password } = ctx.request.body;
|
|
92
92
|
|
|
93
|
-
const user = await getService('user').fetch(
|
|
93
|
+
const user = await getService('user').fetch(id);
|
|
94
|
+
if (!user) {
|
|
95
|
+
throw new NotFoundError(`User not found`);
|
|
96
|
+
}
|
|
94
97
|
|
|
95
98
|
await validateUpdateUserBody(ctx.request.body);
|
|
96
99
|
|
|
@@ -133,8 +136,8 @@ module.exports = {
|
|
|
133
136
|
* Retrieve user records.
|
|
134
137
|
* @return {Object|Array}
|
|
135
138
|
*/
|
|
136
|
-
async find(ctx
|
|
137
|
-
const users = await getService('user').fetchAll(ctx.query
|
|
139
|
+
async find(ctx) {
|
|
140
|
+
const users = await getService('user').fetchAll(ctx.query);
|
|
138
141
|
|
|
139
142
|
ctx.body = await Promise.all(users.map(user => sanitizeOutput(user, ctx)));
|
|
140
143
|
},
|
|
@@ -145,7 +148,9 @@ module.exports = {
|
|
|
145
148
|
*/
|
|
146
149
|
async findOne(ctx) {
|
|
147
150
|
const { id } = ctx.params;
|
|
148
|
-
|
|
151
|
+
const { query } = ctx;
|
|
152
|
+
|
|
153
|
+
let data = await getService('user').fetch(id, query);
|
|
149
154
|
|
|
150
155
|
if (data) {
|
|
151
156
|
data = await sanitizeOutput(data, ctx);
|
|
@@ -3,7 +3,16 @@
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
|
|
5
5
|
const invalidPatternsRegexes = [/<%[^=]([^<>%]*)%>/m, /\${([^{}]*)}/m];
|
|
6
|
-
const authorizedKeys = [
|
|
6
|
+
const authorizedKeys = [
|
|
7
|
+
'URL',
|
|
8
|
+
'ADMIN_URL',
|
|
9
|
+
'SERVER_URL',
|
|
10
|
+
'CODE',
|
|
11
|
+
'USER',
|
|
12
|
+
'USER.email',
|
|
13
|
+
'USER.username',
|
|
14
|
+
'TOKEN',
|
|
15
|
+
];
|
|
7
16
|
|
|
8
17
|
const matchAll = (pattern, src) => {
|
|
9
18
|
const matches = [];
|
|
@@ -19,7 +19,7 @@ module.exports = ({ nexus, strapi }) => {
|
|
|
19
19
|
async resolve(parent, args, context) {
|
|
20
20
|
const { koaContext } = context;
|
|
21
21
|
|
|
22
|
-
koaContext.
|
|
22
|
+
koaContext.query = toPlainObject(args);
|
|
23
23
|
|
|
24
24
|
await strapi
|
|
25
25
|
.plugin('users-permissions')
|
|
@@ -26,12 +26,12 @@ module.exports = ({ strapi }) => {
|
|
|
26
26
|
|
|
27
27
|
// Scoped auth for replaced CRUD operations
|
|
28
28
|
// Role
|
|
29
|
-
[`Mutation.${createRole}`]: { auth: { scope: [`${roleUID}.
|
|
30
|
-
[`Mutation.${updateRole}`]: { auth: { scope: [`${roleUID}.
|
|
31
|
-
[`Mutation.${deleteRole}`]: { auth: { scope: [`${roleUID}.
|
|
29
|
+
[`Mutation.${createRole}`]: { auth: { scope: [`${roleUID}.createRole`] } },
|
|
30
|
+
[`Mutation.${updateRole}`]: { auth: { scope: [`${roleUID}.updateRole`] } },
|
|
31
|
+
[`Mutation.${deleteRole}`]: { auth: { scope: [`${roleUID}.deleteRole`] } },
|
|
32
32
|
// User
|
|
33
33
|
[`Mutation.${createUser}`]: { auth: { scope: [`${userUID}.create`] } },
|
|
34
34
|
[`Mutation.${updateUser}`]: { auth: { scope: [`${userUID}.update`] } },
|
|
35
|
-
[`Mutation.${deleteUser}`]: { auth: { scope: [`${userUID}.
|
|
35
|
+
[`Mutation.${deleteUser}`]: { auth: { scope: [`${userUID}.destroy`] } },
|
|
36
36
|
};
|
|
37
37
|
};
|
package/server/register.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const authStrategy = require('./strategies/users-permissions');
|
|
4
|
+
const sanitizers = require('./utils/sanitize/sanitizers');
|
|
4
5
|
|
|
5
6
|
module.exports = ({ strapi }) => {
|
|
6
7
|
strapi.container.get('auth').register('content-api', authStrategy);
|
|
8
|
+
strapi.sanitizers.add('content-api.output', sanitizers.defaultSanitizeOutput);
|
|
7
9
|
|
|
8
10
|
if (strapi.plugin('graphql')) {
|
|
9
11
|
require('./graphql')({ strapi });
|
|
@@ -4,7 +4,7 @@ module.exports = [
|
|
|
4
4
|
{
|
|
5
5
|
method: 'GET',
|
|
6
6
|
path: '/roles/:id',
|
|
7
|
-
handler: 'role.
|
|
7
|
+
handler: 'role.findOne',
|
|
8
8
|
config: {
|
|
9
9
|
policies: [
|
|
10
10
|
{
|
|
@@ -19,7 +19,7 @@ module.exports = [
|
|
|
19
19
|
{
|
|
20
20
|
method: 'GET',
|
|
21
21
|
path: '/roles',
|
|
22
|
-
handler: 'role.
|
|
22
|
+
handler: 'role.find',
|
|
23
23
|
config: {
|
|
24
24
|
policies: [
|
|
25
25
|
{
|