@strapi/plugin-users-permissions 0.0.0-4fc90398602f
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/LICENSE +22 -0
- package/README.md +1 -0
- package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
- package/admin/src/components/BoundRoute/index.js +72 -0
- package/admin/src/components/FormModal/Input/index.js +121 -0
- package/admin/src/components/FormModal/index.js +121 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +30 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +114 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +53 -0
- package/admin/src/components/Permissions/index.js +56 -0
- package/admin/src/components/Permissions/init.js +9 -0
- package/admin/src/components/Permissions/reducer.js +27 -0
- package/admin/src/components/Policies/index.js +60 -0
- package/admin/src/components/UsersPermissions/index.js +94 -0
- package/admin/src/components/UsersPermissions/init.js +10 -0
- package/admin/src/components/UsersPermissions/reducer.js +60 -0
- package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
- package/admin/src/hooks/index.js +5 -0
- package/admin/src/hooks/useFetchRole/index.js +64 -0
- package/admin/src/hooks/useFetchRole/reducer.js +31 -0
- package/admin/src/hooks/useForm/index.js +70 -0
- package/admin/src/hooks/useForm/reducer.js +40 -0
- package/admin/src/hooks/usePlugins/index.js +65 -0
- package/admin/src/hooks/usePlugins/init.js +5 -0
- package/admin/src/hooks/usePlugins/reducer.js +34 -0
- package/admin/src/hooks/useRolesList/index.js +63 -0
- package/admin/src/hooks/useRolesList/init.js +5 -0
- package/admin/src/hooks/useRolesList/reducer.js +31 -0
- package/admin/src/index.js +123 -0
- package/admin/src/pages/AdvancedSettings/index.js +238 -0
- package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
- package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
- package/admin/src/pages/AdvancedSettings/utils/schema.js +19 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +121 -0
- package/admin/src/pages/EmailTemplates/index.js +162 -0
- package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
- package/admin/src/pages/EmailTemplates/utils/schema.js +22 -0
- package/admin/src/pages/Providers/index.js +274 -0
- package/admin/src/pages/Providers/reducer.js +54 -0
- package/admin/src/pages/Providers/utils/api.js +21 -0
- package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
- package/admin/src/pages/Providers/utils/forms.js +244 -0
- package/admin/src/pages/Roles/CreatePage/index.js +177 -0
- package/admin/src/pages/Roles/CreatePage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/EditPage/index.js +190 -0
- package/admin/src/pages/Roles/EditPage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
- package/admin/src/pages/Roles/ListPage/index.js +216 -0
- package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
- package/admin/src/pages/Roles/ProtectedCreatePage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedEditPage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedListPage/index.js +15 -0
- package/admin/src/pages/Roles/index.js +27 -0
- package/admin/src/permissions.js +31 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/translations/ar.json +40 -0
- package/admin/src/translations/cs.json +46 -0
- package/admin/src/translations/de.json +58 -0
- package/admin/src/translations/dk.json +83 -0
- package/admin/src/translations/en.json +83 -0
- package/admin/src/translations/es.json +83 -0
- package/admin/src/translations/fr.json +46 -0
- package/admin/src/translations/id.json +58 -0
- package/admin/src/translations/it.json +58 -0
- package/admin/src/translations/ja.json +44 -0
- package/admin/src/translations/ko.json +83 -0
- package/admin/src/translations/ms.json +45 -0
- package/admin/src/translations/nl.json +44 -0
- package/admin/src/translations/pl.json +83 -0
- package/admin/src/translations/pt-BR.json +40 -0
- package/admin/src/translations/pt.json +44 -0
- package/admin/src/translations/ru.json +58 -0
- package/admin/src/translations/sk.json +46 -0
- package/admin/src/translations/sv.json +58 -0
- package/admin/src/translations/th.json +56 -0
- package/admin/src/translations/tr.json +44 -0
- package/admin/src/translations/uk.json +45 -0
- package/admin/src/translations/vi.json +46 -0
- package/admin/src/translations/zh-Hans.json +62 -0
- package/admin/src/translations/zh.json +44 -0
- package/admin/src/utils/axiosInstance.js +36 -0
- package/admin/src/utils/cleanPermissions.js +25 -0
- package/admin/src/utils/formatPluginName.js +26 -0
- package/admin/src/utils/formatPolicies.js +8 -0
- package/admin/src/utils/getRequestURL.js +5 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/admin/src/utils/index.js +5 -0
- package/documentation/content-api.yaml +848 -0
- package/jest.config.front.js +10 -0
- package/package.json +60 -0
- package/server/bootstrap/grant-config.js +123 -0
- package/server/bootstrap/index.js +133 -0
- package/server/bootstrap/users-permissions-actions.js +80 -0
- package/server/config.js +23 -0
- package/server/content-types/index.js +11 -0
- package/server/content-types/permission/index.js +34 -0
- package/server/content-types/role/index.js +51 -0
- package/server/content-types/user/index.js +72 -0
- package/server/content-types/user/schema-config.js +15 -0
- package/server/controllers/auth.js +398 -0
- package/server/controllers/content-manager-user.js +175 -0
- package/server/controllers/index.js +17 -0
- package/server/controllers/permissions.js +26 -0
- package/server/controllers/role.js +77 -0
- package/server/controllers/settings.js +85 -0
- package/server/controllers/user.js +198 -0
- package/server/controllers/validation/auth.js +57 -0
- package/server/controllers/validation/email-template.js +50 -0
- package/server/controllers/validation/user.js +26 -0
- package/server/graphql/index.js +44 -0
- package/server/graphql/mutations/auth/change-password.js +38 -0
- package/server/graphql/mutations/auth/email-confirmation.js +39 -0
- package/server/graphql/mutations/auth/forgot-password.js +35 -0
- package/server/graphql/mutations/auth/login.js +35 -0
- package/server/graphql/mutations/auth/register.js +36 -0
- package/server/graphql/mutations/auth/reset-password.js +38 -0
- package/server/graphql/mutations/crud/role/create-role.js +34 -0
- package/server/graphql/mutations/crud/role/delete-role.js +25 -0
- package/server/graphql/mutations/crud/role/update-role.js +35 -0
- package/server/graphql/mutations/crud/user/create-user.js +45 -0
- package/server/graphql/mutations/crud/user/delete-user.js +39 -0
- package/server/graphql/mutations/crud/user/update-user.js +46 -0
- package/server/graphql/mutations/index.js +43 -0
- package/server/graphql/queries/index.js +13 -0
- package/server/graphql/queries/me.js +17 -0
- package/server/graphql/resolvers-configs.js +42 -0
- package/server/graphql/types/create-role-payload.js +11 -0
- package/server/graphql/types/delete-role-payload.js +11 -0
- package/server/graphql/types/index.js +21 -0
- package/server/graphql/types/login-input.js +13 -0
- package/server/graphql/types/login-payload.js +12 -0
- package/server/graphql/types/me-role.js +14 -0
- package/server/graphql/types/me.js +16 -0
- package/server/graphql/types/password-payload.js +11 -0
- package/server/graphql/types/register-input.js +13 -0
- package/server/graphql/types/update-role-payload.js +11 -0
- package/server/graphql/utils.js +27 -0
- package/server/index.js +21 -0
- package/server/middlewares/index.js +7 -0
- package/server/middlewares/rateLimit.js +27 -0
- package/server/register.js +23 -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 +82 -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 +60 -0
- package/server/routes/index.js +6 -0
- package/server/services/index.js +17 -0
- package/server/services/jwt.js +55 -0
- package/server/services/providers-registry.js +292 -0
- package/server/services/providers.js +115 -0
- package/server/services/role.js +177 -0
- package/server/services/user.js +140 -0
- package/server/services/users-permissions.js +236 -0
- package/server/strategies/users-permissions.js +102 -0
- package/server/utils/index.d.ts +16 -0
- package/server/utils/index.js +12 -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
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
5
|
+
const { getService } = require('../utils');
|
|
6
|
+
const { isValidEmailTemplate } = require('./validation/email-template');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
async getEmailTemplate(ctx) {
|
|
10
|
+
ctx.send(await strapi.store({ type: 'plugin', name: 'users-permissions', key: 'email' }).get());
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async updateEmailTemplate(ctx) {
|
|
14
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
15
|
+
throw new ValidationError('Request body cannot be empty');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const emailTemplates = ctx.request.body['email-templates'];
|
|
19
|
+
|
|
20
|
+
for (const key of Object.keys(emailTemplates)) {
|
|
21
|
+
const template = emailTemplates[key].options.message;
|
|
22
|
+
|
|
23
|
+
if (!isValidEmailTemplate(template)) {
|
|
24
|
+
throw new ValidationError('Invalid template');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await strapi
|
|
29
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'email' })
|
|
30
|
+
.set({ value: emailTemplates });
|
|
31
|
+
|
|
32
|
+
ctx.send({ ok: true });
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
async getAdvancedSettings(ctx) {
|
|
36
|
+
const settings = await strapi
|
|
37
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
38
|
+
.get();
|
|
39
|
+
|
|
40
|
+
const roles = await getService('role').find();
|
|
41
|
+
|
|
42
|
+
ctx.send({ settings, roles });
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async updateAdvancedSettings(ctx) {
|
|
46
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
47
|
+
throw new ValidationError('Request body cannot be empty');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await strapi
|
|
51
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
52
|
+
.set({ value: ctx.request.body });
|
|
53
|
+
|
|
54
|
+
ctx.send({ ok: true });
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
async getProviders(ctx) {
|
|
58
|
+
const providers = await strapi
|
|
59
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
60
|
+
.get();
|
|
61
|
+
|
|
62
|
+
for (const provider in providers) {
|
|
63
|
+
if (provider !== 'email') {
|
|
64
|
+
providers[provider].redirectUri = strapi
|
|
65
|
+
.plugin('users-permissions')
|
|
66
|
+
.service('providers')
|
|
67
|
+
.buildRedirectUri(provider);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ctx.send(providers);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async updateProviders(ctx) {
|
|
75
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
76
|
+
throw new ValidationError('Request body cannot be empty');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await strapi
|
|
80
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
81
|
+
.set({ value: ctx.request.body.providers });
|
|
82
|
+
|
|
83
|
+
ctx.send({ ok: true });
|
|
84
|
+
},
|
|
85
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* User.js controller
|
|
5
|
+
*
|
|
6
|
+
* @description: A set of functions called "actions" for managing `User`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const _ = require('lodash');
|
|
10
|
+
const utils = require('@strapi/utils');
|
|
11
|
+
const { getService } = require('../utils');
|
|
12
|
+
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
13
|
+
|
|
14
|
+
const { sanitize } = utils;
|
|
15
|
+
const { ApplicationError, ValidationError, NotFoundError } = utils.errors;
|
|
16
|
+
|
|
17
|
+
const sanitizeOutput = (user, ctx) => {
|
|
18
|
+
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
19
|
+
const { auth } = ctx.state;
|
|
20
|
+
|
|
21
|
+
return sanitize.contentAPI.output(user, schema, { auth });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
/**
|
|
26
|
+
* Create a/an user record.
|
|
27
|
+
* @return {Object}
|
|
28
|
+
*/
|
|
29
|
+
async create(ctx) {
|
|
30
|
+
const advanced = await strapi
|
|
31
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
32
|
+
.get();
|
|
33
|
+
|
|
34
|
+
await validateCreateUserBody(ctx.request.body);
|
|
35
|
+
|
|
36
|
+
const { email, username, role } = ctx.request.body;
|
|
37
|
+
|
|
38
|
+
const userWithSameUsername = await strapi
|
|
39
|
+
.query('plugin::users-permissions.user')
|
|
40
|
+
.findOne({ where: { username } });
|
|
41
|
+
|
|
42
|
+
if (userWithSameUsername) {
|
|
43
|
+
if (!email) throw new ApplicationError('Username already taken');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (advanced.unique_email) {
|
|
47
|
+
const userWithSameEmail = await strapi
|
|
48
|
+
.query('plugin::users-permissions.user')
|
|
49
|
+
.findOne({ where: { email: email.toLowerCase() } });
|
|
50
|
+
|
|
51
|
+
if (userWithSameEmail) {
|
|
52
|
+
throw new ApplicationError('Email already taken');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const user = {
|
|
57
|
+
...ctx.request.body,
|
|
58
|
+
email: email.toLowerCase(),
|
|
59
|
+
provider: 'local',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (!role) {
|
|
63
|
+
const defaultRole = await strapi
|
|
64
|
+
.query('plugin::users-permissions.role')
|
|
65
|
+
.findOne({ where: { type: advanced.default_role } });
|
|
66
|
+
|
|
67
|
+
user.role = defaultRole.id;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const data = await getService('user').add(user);
|
|
72
|
+
const sanitizedData = await sanitizeOutput(data, ctx);
|
|
73
|
+
|
|
74
|
+
ctx.created(sanitizedData);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new ApplicationError(error.message);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Update a/an user record.
|
|
82
|
+
* @return {Object}
|
|
83
|
+
*/
|
|
84
|
+
async update(ctx) {
|
|
85
|
+
const advancedConfigs = await strapi
|
|
86
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
87
|
+
.get();
|
|
88
|
+
|
|
89
|
+
const { id } = ctx.params;
|
|
90
|
+
const { email, username, password } = ctx.request.body;
|
|
91
|
+
|
|
92
|
+
const user = await getService('user').fetch(id);
|
|
93
|
+
if (!user) {
|
|
94
|
+
throw new NotFoundError(`User not found`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
await validateUpdateUserBody(ctx.request.body);
|
|
98
|
+
|
|
99
|
+
if (user.provider === 'local' && _.has(ctx.request.body, 'password') && !password) {
|
|
100
|
+
throw new ValidationError('password.notNull');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (_.has(ctx.request.body, 'username')) {
|
|
104
|
+
const userWithSameUsername = await strapi
|
|
105
|
+
.query('plugin::users-permissions.user')
|
|
106
|
+
.findOne({ where: { username } });
|
|
107
|
+
|
|
108
|
+
if (userWithSameUsername && userWithSameUsername.id != id) {
|
|
109
|
+
throw new ApplicationError('Username already taken');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
|
|
114
|
+
const userWithSameEmail = await strapi
|
|
115
|
+
.query('plugin::users-permissions.user')
|
|
116
|
+
.findOne({ where: { email: email.toLowerCase() } });
|
|
117
|
+
|
|
118
|
+
if (userWithSameEmail && userWithSameEmail.id != id) {
|
|
119
|
+
throw new ApplicationError('Email already taken');
|
|
120
|
+
}
|
|
121
|
+
ctx.request.body.email = ctx.request.body.email.toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const updateData = {
|
|
125
|
+
...ctx.request.body,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const data = await getService('user').edit(user.id, updateData);
|
|
129
|
+
const sanitizedData = await sanitizeOutput(data, ctx);
|
|
130
|
+
|
|
131
|
+
ctx.send(sanitizedData);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Retrieve user records.
|
|
136
|
+
* @return {Object|Array}
|
|
137
|
+
*/
|
|
138
|
+
async find(ctx) {
|
|
139
|
+
const users = await getService('user').fetchAll(ctx.query);
|
|
140
|
+
|
|
141
|
+
ctx.body = await Promise.all(users.map((user) => sanitizeOutput(user, ctx)));
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Retrieve a user record.
|
|
146
|
+
* @return {Object}
|
|
147
|
+
*/
|
|
148
|
+
async findOne(ctx) {
|
|
149
|
+
const { id } = ctx.params;
|
|
150
|
+
const { query } = ctx;
|
|
151
|
+
|
|
152
|
+
let data = await getService('user').fetch(id, query);
|
|
153
|
+
|
|
154
|
+
if (data) {
|
|
155
|
+
data = await sanitizeOutput(data, ctx);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
ctx.body = data;
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Retrieve user count.
|
|
163
|
+
* @return {Number}
|
|
164
|
+
*/
|
|
165
|
+
async count(ctx) {
|
|
166
|
+
ctx.body = await getService('user').count(ctx.query);
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Destroy a/an user record.
|
|
171
|
+
* @return {Object}
|
|
172
|
+
*/
|
|
173
|
+
async destroy(ctx) {
|
|
174
|
+
const { id } = ctx.params;
|
|
175
|
+
|
|
176
|
+
const data = await getService('user').remove({ id });
|
|
177
|
+
const sanitizedUser = await sanitizeOutput(data, ctx);
|
|
178
|
+
|
|
179
|
+
ctx.send(sanitizedUser);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Retrieve authenticated user.
|
|
184
|
+
* @return {Object|Array}
|
|
185
|
+
*/
|
|
186
|
+
async me(ctx) {
|
|
187
|
+
const authUser = ctx.state.user;
|
|
188
|
+
const { query } = ctx;
|
|
189
|
+
|
|
190
|
+
if (!authUser) {
|
|
191
|
+
return ctx.unauthorized();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const user = await getService('user').fetch(authUser.id, query);
|
|
195
|
+
|
|
196
|
+
ctx.body = await sanitizeOutput(user, ctx);
|
|
197
|
+
},
|
|
198
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { yup, validateYupSchema } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const callbackSchema = yup.object({
|
|
6
|
+
identifier: yup.string().required(),
|
|
7
|
+
password: yup.string().required(),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const registerSchema = yup.object({
|
|
11
|
+
email: yup.string().email().required(),
|
|
12
|
+
username: yup.string().required(),
|
|
13
|
+
password: yup.string().required(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const sendEmailConfirmationSchema = yup.object({
|
|
17
|
+
email: yup.string().email().required(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const validateEmailConfirmationSchema = yup.object({
|
|
21
|
+
confirmation: yup.string().required(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const forgotPasswordSchema = yup
|
|
25
|
+
.object({
|
|
26
|
+
email: yup.string().email().required(),
|
|
27
|
+
})
|
|
28
|
+
.noUnknown();
|
|
29
|
+
|
|
30
|
+
const resetPasswordSchema = yup
|
|
31
|
+
.object({
|
|
32
|
+
password: yup.string().required(),
|
|
33
|
+
passwordConfirmation: yup.string().required(),
|
|
34
|
+
code: yup.string().required(),
|
|
35
|
+
})
|
|
36
|
+
.noUnknown();
|
|
37
|
+
|
|
38
|
+
const changePasswordSchema = yup
|
|
39
|
+
.object({
|
|
40
|
+
password: yup.string().required(),
|
|
41
|
+
passwordConfirmation: yup
|
|
42
|
+
.string()
|
|
43
|
+
.required()
|
|
44
|
+
.oneOf([yup.ref('password')], 'Passwords do not match'),
|
|
45
|
+
currentPassword: yup.string().required(),
|
|
46
|
+
})
|
|
47
|
+
.noUnknown();
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
validateCallbackBody: validateYupSchema(callbackSchema),
|
|
51
|
+
validateRegisterBody: validateYupSchema(registerSchema),
|
|
52
|
+
validateSendEmailConfirmationBody: validateYupSchema(sendEmailConfirmationSchema),
|
|
53
|
+
validateEmailConfirmationBody: validateYupSchema(validateEmailConfirmationSchema),
|
|
54
|
+
validateForgotPasswordBody: validateYupSchema(forgotPasswordSchema),
|
|
55
|
+
validateResetPasswordBody: validateYupSchema(resetPasswordSchema),
|
|
56
|
+
validateChangePasswordBody: validateYupSchema(changePasswordSchema),
|
|
57
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
const invalidPatternsRegexes = [/<%[^=]([^<>%]*)%>/m, /\${([^{}]*)}/m];
|
|
6
|
+
const authorizedKeys = [
|
|
7
|
+
'URL',
|
|
8
|
+
'ADMIN_URL',
|
|
9
|
+
'SERVER_URL',
|
|
10
|
+
'CODE',
|
|
11
|
+
'USER',
|
|
12
|
+
'USER.email',
|
|
13
|
+
'USER.username',
|
|
14
|
+
'TOKEN',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const matchAll = (pattern, src) => {
|
|
18
|
+
const matches = [];
|
|
19
|
+
let match;
|
|
20
|
+
|
|
21
|
+
const regexPatternWithGlobal = RegExp(pattern, 'g');
|
|
22
|
+
// eslint-disable-next-line no-cond-assign
|
|
23
|
+
while ((match = regexPatternWithGlobal.exec(src))) {
|
|
24
|
+
const [, group] = match;
|
|
25
|
+
|
|
26
|
+
matches.push(_.trim(group));
|
|
27
|
+
}
|
|
28
|
+
return matches;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const isValidEmailTemplate = (template) => {
|
|
32
|
+
for (const reg of invalidPatternsRegexes) {
|
|
33
|
+
if (reg.test(template)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const matches = matchAll(/<%=([^<>%=]*)%>/, template);
|
|
39
|
+
for (const match of matches) {
|
|
40
|
+
if (!authorizedKeys.includes(match)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return true;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
isValidEmailTemplate,
|
|
50
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { yup, validateYupSchema } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const deleteRoleSchema = yup.object().shape({
|
|
6
|
+
role: yup.strapiID().required(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const createUserBodySchema = yup.object().shape({
|
|
10
|
+
email: yup.string().email().required(),
|
|
11
|
+
username: yup.string().min(1).required(),
|
|
12
|
+
password: yup.string().min(1).required(),
|
|
13
|
+
role: yup.strapiID(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const updateUserBodySchema = yup.object().shape({
|
|
17
|
+
email: yup.string().email().min(1),
|
|
18
|
+
username: yup.string().min(1),
|
|
19
|
+
password: yup.string().min(1),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
validateCreateUserBody: validateYupSchema(createUserBodySchema),
|
|
24
|
+
validateUpdateUserBody: validateYupSchema(updateUserBodySchema),
|
|
25
|
+
validateDeleteRoleBody: validateYupSchema(deleteRoleSchema),
|
|
26
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getTypes = require('./types');
|
|
4
|
+
const getQueries = require('./queries');
|
|
5
|
+
const getMutations = require('./mutations');
|
|
6
|
+
const getResolversConfig = require('./resolvers-configs');
|
|
7
|
+
|
|
8
|
+
module.exports = ({ strapi }) => {
|
|
9
|
+
const { config: graphQLConfig } = strapi.plugin('graphql');
|
|
10
|
+
const extensionService = strapi.plugin('graphql').service('extension');
|
|
11
|
+
|
|
12
|
+
const isShadowCRUDEnabled = graphQLConfig('shadowCRUD', true);
|
|
13
|
+
|
|
14
|
+
if (!isShadowCRUDEnabled) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Disable Permissions queries & mutations but allow the
|
|
19
|
+
// type to be used/selected in filters or nested resolvers
|
|
20
|
+
extensionService
|
|
21
|
+
.shadowCRUD('plugin::users-permissions.permission')
|
|
22
|
+
.disableQueries()
|
|
23
|
+
.disableMutations();
|
|
24
|
+
|
|
25
|
+
// Disable User & Role's Create/Update/Delete actions so they can be replaced
|
|
26
|
+
const actionsToDisable = ['create', 'update', 'delete'];
|
|
27
|
+
|
|
28
|
+
extensionService.shadowCRUD('plugin::users-permissions.user').disableActions(actionsToDisable);
|
|
29
|
+
extensionService.shadowCRUD('plugin::users-permissions.role').disableActions(actionsToDisable);
|
|
30
|
+
|
|
31
|
+
// Register new types & resolvers config
|
|
32
|
+
extensionService.use(({ nexus }) => {
|
|
33
|
+
const types = getTypes({ strapi, nexus });
|
|
34
|
+
const queries = getQueries({ strapi, nexus });
|
|
35
|
+
const mutations = getMutations({ strapi, nexus });
|
|
36
|
+
const resolversConfig = getResolversConfig({ strapi });
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
types: [types, queries, mutations],
|
|
40
|
+
|
|
41
|
+
resolversConfig,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: 'UsersPermissionsLoginPayload',
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
currentPassword: nonNull('String'),
|
|
15
|
+
password: nonNull('String'),
|
|
16
|
+
passwordConfirmation: nonNull('String'),
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
description: 'Change user password. Confirm with the current password.',
|
|
20
|
+
|
|
21
|
+
async resolve(parent, args, context) {
|
|
22
|
+
const { koaContext } = context;
|
|
23
|
+
|
|
24
|
+
koaContext.request.body = toPlainObject(args);
|
|
25
|
+
|
|
26
|
+
await strapi.plugin('users-permissions').controller('auth').changePassword(koaContext);
|
|
27
|
+
|
|
28
|
+
const output = koaContext.body;
|
|
29
|
+
|
|
30
|
+
checkBadRequest(output);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
user: output.user || output,
|
|
34
|
+
jwt: output.jwt,
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: 'UsersPermissionsLoginPayload',
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
confirmation: nonNull('String'),
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
description: 'Confirm an email users email address',
|
|
18
|
+
|
|
19
|
+
async resolve(parent, args, context) {
|
|
20
|
+
const { koaContext } = context;
|
|
21
|
+
|
|
22
|
+
koaContext.query = toPlainObject(args);
|
|
23
|
+
|
|
24
|
+
await strapi
|
|
25
|
+
.plugin('users-permissions')
|
|
26
|
+
.controller('auth')
|
|
27
|
+
.emailConfirmation(koaContext, null, true);
|
|
28
|
+
|
|
29
|
+
const output = koaContext.body;
|
|
30
|
+
|
|
31
|
+
checkBadRequest(output);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
user: output.user || output,
|
|
35
|
+
jwt: output.jwt,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: 'UsersPermissionsPasswordPayload',
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
email: nonNull('String'),
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
description: 'Request a reset password token',
|
|
18
|
+
|
|
19
|
+
async resolve(parent, args, context) {
|
|
20
|
+
const { koaContext } = context;
|
|
21
|
+
|
|
22
|
+
koaContext.request.body = toPlainObject(args);
|
|
23
|
+
|
|
24
|
+
await strapi.plugin('users-permissions').controller('auth').forgotPassword(koaContext);
|
|
25
|
+
|
|
26
|
+
const output = koaContext.body;
|
|
27
|
+
|
|
28
|
+
checkBadRequest(output);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
ok: output.ok || output,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: nonNull('UsersPermissionsLoginPayload'),
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
input: nonNull('UsersPermissionsLoginInput'),
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
async resolve(parent, args, context) {
|
|
18
|
+
const { koaContext } = context;
|
|
19
|
+
|
|
20
|
+
koaContext.params = { provider: args.input.provider };
|
|
21
|
+
koaContext.request.body = toPlainObject(args.input);
|
|
22
|
+
|
|
23
|
+
await strapi.plugin('users-permissions').controller('auth').callback(koaContext);
|
|
24
|
+
|
|
25
|
+
const output = koaContext.body;
|
|
26
|
+
|
|
27
|
+
checkBadRequest(output);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
user: output.user || output,
|
|
31
|
+
jwt: output.jwt,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: nonNull('UsersPermissionsLoginPayload'),
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
input: nonNull('UsersPermissionsRegisterInput'),
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
description: 'Register a user',
|
|
18
|
+
|
|
19
|
+
async resolve(parent, args, context) {
|
|
20
|
+
const { koaContext } = context;
|
|
21
|
+
|
|
22
|
+
koaContext.request.body = toPlainObject(args.input);
|
|
23
|
+
|
|
24
|
+
await strapi.plugin('users-permissions').controller('auth').register(koaContext);
|
|
25
|
+
|
|
26
|
+
const output = koaContext.body;
|
|
27
|
+
|
|
28
|
+
checkBadRequest(output);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
user: output.user || output,
|
|
32
|
+
jwt: output.jwt,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toPlainObject } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ nexus, strapi }) => {
|
|
8
|
+
const { nonNull } = nexus;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: 'UsersPermissionsLoginPayload',
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
password: nonNull('String'),
|
|
15
|
+
passwordConfirmation: nonNull('String'),
|
|
16
|
+
code: nonNull('String'),
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
description: 'Reset user password. Confirm with a code (resetToken from forgotPassword)',
|
|
20
|
+
|
|
21
|
+
async resolve(parent, args, context) {
|
|
22
|
+
const { koaContext } = context;
|
|
23
|
+
|
|
24
|
+
koaContext.request.body = toPlainObject(args);
|
|
25
|
+
|
|
26
|
+
await strapi.plugin('users-permissions').controller('auth').resetPassword(koaContext);
|
|
27
|
+
|
|
28
|
+
const output = koaContext.body;
|
|
29
|
+
|
|
30
|
+
checkBadRequest(output);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
user: output.user || output,
|
|
34
|
+
jwt: output.jwt,
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|