@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,292 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { strict: assert } = require('assert');
|
|
4
|
+
const jwt = require('jsonwebtoken');
|
|
5
|
+
|
|
6
|
+
const getInitialProviders = ({ purest }) => ({
|
|
7
|
+
async discord({ accessToken }) {
|
|
8
|
+
const discord = purest({ provider: 'discord' });
|
|
9
|
+
return discord
|
|
10
|
+
.get('users/@me')
|
|
11
|
+
.auth(accessToken)
|
|
12
|
+
.request()
|
|
13
|
+
.then(({ body }) => {
|
|
14
|
+
// Combine username and discriminator because discord username is not unique
|
|
15
|
+
const username = `${body.username}#${body.discriminator}`;
|
|
16
|
+
return {
|
|
17
|
+
username,
|
|
18
|
+
email: body.email,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
async cognito({ query }) {
|
|
23
|
+
// get the id_token
|
|
24
|
+
const idToken = query.id_token;
|
|
25
|
+
// decode the jwt token
|
|
26
|
+
const tokenPayload = jwt.decode(idToken);
|
|
27
|
+
if (!tokenPayload) {
|
|
28
|
+
throw new Error('unable to decode jwt token');
|
|
29
|
+
} else {
|
|
30
|
+
return {
|
|
31
|
+
username: tokenPayload['cognito:username'],
|
|
32
|
+
email: tokenPayload.email,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
async facebook({ accessToken }) {
|
|
37
|
+
const facebook = purest({ provider: 'facebook' });
|
|
38
|
+
|
|
39
|
+
return facebook
|
|
40
|
+
.get('me')
|
|
41
|
+
.auth(accessToken)
|
|
42
|
+
.qs({ fields: 'name,email' })
|
|
43
|
+
.request()
|
|
44
|
+
.then(({ body }) => ({
|
|
45
|
+
username: body.name,
|
|
46
|
+
email: body.email,
|
|
47
|
+
}));
|
|
48
|
+
},
|
|
49
|
+
async google({ accessToken }) {
|
|
50
|
+
const google = purest({ provider: 'google' });
|
|
51
|
+
|
|
52
|
+
return google
|
|
53
|
+
.query('oauth')
|
|
54
|
+
.get('tokeninfo')
|
|
55
|
+
.qs({ accessToken })
|
|
56
|
+
.request()
|
|
57
|
+
.then(({ body }) => ({
|
|
58
|
+
username: body.email.split('@')[0],
|
|
59
|
+
email: body.email,
|
|
60
|
+
}));
|
|
61
|
+
},
|
|
62
|
+
async github({ accessToken }) {
|
|
63
|
+
const github = purest({
|
|
64
|
+
provider: 'github',
|
|
65
|
+
defaults: {
|
|
66
|
+
headers: {
|
|
67
|
+
'user-agent': 'strapi',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const { body: userBody } = await github.get('user').auth(accessToken).request();
|
|
73
|
+
|
|
74
|
+
// This is the public email on the github profile
|
|
75
|
+
if (userBody.email) {
|
|
76
|
+
return {
|
|
77
|
+
username: userBody.login,
|
|
78
|
+
email: userBody.email,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Get the email with Github's user/emails API
|
|
82
|
+
const { body: emailBody } = await github.get('user/emails').auth(accessToken).request();
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
username: userBody.login,
|
|
86
|
+
email: Array.isArray(emailBody)
|
|
87
|
+
? emailBody.find((email) => email.primary === true).email
|
|
88
|
+
: null,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
async microsoft({ accessToken }) {
|
|
92
|
+
const microsoft = purest({ provider: 'microsoft' });
|
|
93
|
+
|
|
94
|
+
return microsoft
|
|
95
|
+
.get('me')
|
|
96
|
+
.auth(accessToken)
|
|
97
|
+
.request()
|
|
98
|
+
.then(({ body }) => ({
|
|
99
|
+
username: body.userPrincipalName,
|
|
100
|
+
email: body.userPrincipalName,
|
|
101
|
+
}));
|
|
102
|
+
},
|
|
103
|
+
async twitter({ accessToken, query, providers }) {
|
|
104
|
+
const twitter = purest({
|
|
105
|
+
provider: 'twitter',
|
|
106
|
+
defaults: {
|
|
107
|
+
oauth: {
|
|
108
|
+
consumer_key: providers.twitter.key,
|
|
109
|
+
consumer_secret: providers.twitter.secret,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return twitter
|
|
115
|
+
.get('account/verify_credentials')
|
|
116
|
+
.auth(accessToken, query.access_secret)
|
|
117
|
+
.qs({ screen_name: query['raw[screen_name]'], include_email: 'true' })
|
|
118
|
+
.request()
|
|
119
|
+
.then(({ body }) => ({
|
|
120
|
+
username: body.screen_name,
|
|
121
|
+
email: body.email,
|
|
122
|
+
}));
|
|
123
|
+
},
|
|
124
|
+
async instagram({ accessToken }) {
|
|
125
|
+
const instagram = purest({ provider: 'instagram' });
|
|
126
|
+
|
|
127
|
+
return instagram
|
|
128
|
+
.get('me')
|
|
129
|
+
.auth(accessToken)
|
|
130
|
+
.qs({ fields: 'id,username' })
|
|
131
|
+
.request()
|
|
132
|
+
.then(({ body }) => ({
|
|
133
|
+
username: body.username,
|
|
134
|
+
email: `${body.username}@strapi.io`, // dummy email as Instagram does not provide user email
|
|
135
|
+
}));
|
|
136
|
+
},
|
|
137
|
+
async vk({ accessToken, query }) {
|
|
138
|
+
const vk = purest({ provider: 'vk' });
|
|
139
|
+
|
|
140
|
+
return vk
|
|
141
|
+
.get('users.get')
|
|
142
|
+
.auth(accessToken)
|
|
143
|
+
.qs({ id: query.raw.user_id, v: '5.122' })
|
|
144
|
+
.request()
|
|
145
|
+
.then(({ body }) => ({
|
|
146
|
+
username: `${body.response[0].last_name} ${body.response[0].first_name}`,
|
|
147
|
+
email: query.raw.email,
|
|
148
|
+
}));
|
|
149
|
+
},
|
|
150
|
+
async twitch({ accessToken, providers }) {
|
|
151
|
+
const twitch = purest({
|
|
152
|
+
provider: 'twitch',
|
|
153
|
+
config: {
|
|
154
|
+
twitch: {
|
|
155
|
+
default: {
|
|
156
|
+
origin: 'https://api.twitch.tv',
|
|
157
|
+
path: 'helix/{path}',
|
|
158
|
+
headers: {
|
|
159
|
+
Authorization: 'Bearer {auth}',
|
|
160
|
+
'Client-Id': '{auth}',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return twitch
|
|
168
|
+
.get('users')
|
|
169
|
+
.auth(accessToken, providers.twitch.key)
|
|
170
|
+
.request()
|
|
171
|
+
.then(({ body }) => ({
|
|
172
|
+
username: body.data[0].login,
|
|
173
|
+
email: body.data[0].email,
|
|
174
|
+
}));
|
|
175
|
+
},
|
|
176
|
+
async linkedin({ accessToken }) {
|
|
177
|
+
const linkedIn = purest({ provider: 'linkedin' });
|
|
178
|
+
const {
|
|
179
|
+
body: { localizedFirstName },
|
|
180
|
+
} = await linkedIn.get('me').auth(accessToken).request();
|
|
181
|
+
const {
|
|
182
|
+
body: { elements },
|
|
183
|
+
} = await linkedIn
|
|
184
|
+
.get('emailAddress?q=members&projection=(elements*(handle~))')
|
|
185
|
+
.auth(accessToken)
|
|
186
|
+
.request();
|
|
187
|
+
|
|
188
|
+
const email = elements[0]['handle~'];
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
username: localizedFirstName,
|
|
192
|
+
email: email.emailAddress,
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
async reddit({ accessToken }) {
|
|
196
|
+
const reddit = purest({
|
|
197
|
+
provider: 'reddit',
|
|
198
|
+
config: {
|
|
199
|
+
reddit: {
|
|
200
|
+
default: {
|
|
201
|
+
origin: 'https://oauth.reddit.com',
|
|
202
|
+
path: 'api/{version}/{path}',
|
|
203
|
+
version: 'v1',
|
|
204
|
+
headers: {
|
|
205
|
+
Authorization: 'Bearer {auth}',
|
|
206
|
+
'user-agent': 'strapi',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return reddit
|
|
214
|
+
.get('me')
|
|
215
|
+
.auth(accessToken)
|
|
216
|
+
.request()
|
|
217
|
+
.then(({ body }) => ({
|
|
218
|
+
username: body.name,
|
|
219
|
+
email: `${body.name}@strapi.io`, // dummy email as Reddit does not provide user email
|
|
220
|
+
}));
|
|
221
|
+
},
|
|
222
|
+
async auth0({ accessToken, providers }) {
|
|
223
|
+
const auth0 = purest({ provider: 'auth0' });
|
|
224
|
+
|
|
225
|
+
return auth0
|
|
226
|
+
.get('userinfo')
|
|
227
|
+
.subdomain(providers.auth0.subdomain)
|
|
228
|
+
.auth(accessToken)
|
|
229
|
+
.request()
|
|
230
|
+
.then(({ body }) => {
|
|
231
|
+
const username = body.username || body.nickname || body.name || body.email.split('@')[0];
|
|
232
|
+
const email = body.email || `${username.replace(/\s+/g, '.')}@strapi.io`;
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
username,
|
|
236
|
+
email,
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
async cas({ accessToken, providers }) {
|
|
241
|
+
const cas = purest({ provider: 'cas' });
|
|
242
|
+
|
|
243
|
+
return cas
|
|
244
|
+
.get('oidc/profile')
|
|
245
|
+
.subdomain(providers.cas.subdomain)
|
|
246
|
+
.auth(accessToken)
|
|
247
|
+
.request()
|
|
248
|
+
.then(({ body }) => {
|
|
249
|
+
// CAS attribute may be in body.attributes or "FLAT", depending on CAS config
|
|
250
|
+
const username = body.attributes
|
|
251
|
+
? body.attributes.strapiusername || body.id || body.sub
|
|
252
|
+
: body.strapiusername || body.id || body.sub;
|
|
253
|
+
const email = body.attributes
|
|
254
|
+
? body.attributes.strapiemail || body.attributes.email
|
|
255
|
+
: body.strapiemail || body.email;
|
|
256
|
+
if (!username || !email) {
|
|
257
|
+
strapi.log.warn(
|
|
258
|
+
`CAS Response Body did not contain required attributes: ${JSON.stringify(body)}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
username,
|
|
263
|
+
email,
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
module.exports = () => {
|
|
270
|
+
const purest = require('purest');
|
|
271
|
+
|
|
272
|
+
const providersCallbacks = getInitialProviders({ purest });
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
register(providerName, provider) {
|
|
276
|
+
assert(typeof providerName === 'string', 'Provider name must be a string');
|
|
277
|
+
assert(typeof provider === 'function', 'Provider callback must be a function');
|
|
278
|
+
|
|
279
|
+
providersCallbacks[providerName] = provider({ purest });
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
async run({ provider, accessToken, query, providers }) {
|
|
283
|
+
if (!providersCallbacks[provider]) {
|
|
284
|
+
throw new Error('Unknown provider.');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const providerCb = providersCallbacks[provider];
|
|
288
|
+
|
|
289
|
+
return providerCb({ accessToken, query, providers });
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Module dependencies.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Public node modules.
|
|
8
|
+
const _ = require('lodash');
|
|
9
|
+
const urlJoin = require('url-join');
|
|
10
|
+
|
|
11
|
+
const { getAbsoluteServerUrl } = require('@strapi/utils');
|
|
12
|
+
const { getService } = require('../utils');
|
|
13
|
+
|
|
14
|
+
module.exports = ({ strapi }) => {
|
|
15
|
+
/**
|
|
16
|
+
* Helper to get profiles
|
|
17
|
+
*
|
|
18
|
+
* @param {String} provider
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const getProfile = async (provider, query) => {
|
|
22
|
+
const accessToken = query.access_token || query.code || query.oauth_token;
|
|
23
|
+
|
|
24
|
+
const providers = await strapi
|
|
25
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
26
|
+
.get();
|
|
27
|
+
|
|
28
|
+
return getService('providers-registry').run({
|
|
29
|
+
provider,
|
|
30
|
+
query,
|
|
31
|
+
accessToken,
|
|
32
|
+
providers,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Connect thanks to a third-party provider.
|
|
38
|
+
*
|
|
39
|
+
*
|
|
40
|
+
* @param {String} provider
|
|
41
|
+
* @param {String} accessToken
|
|
42
|
+
*
|
|
43
|
+
* @return {*}
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
const connect = async (provider, query) => {
|
|
47
|
+
const accessToken = query.access_token || query.code || query.oauth_token;
|
|
48
|
+
|
|
49
|
+
if (!accessToken) {
|
|
50
|
+
throw new Error('No access_token.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get the profile.
|
|
54
|
+
const profile = await getProfile(provider, query);
|
|
55
|
+
|
|
56
|
+
const email = _.toLower(profile.email);
|
|
57
|
+
|
|
58
|
+
// We need at least the mail.
|
|
59
|
+
if (!email) {
|
|
60
|
+
throw new Error('Email was not available.');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const users = await strapi.query('plugin::users-permissions.user').findMany({
|
|
64
|
+
where: { email },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const advancedSettings = await strapi
|
|
68
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
69
|
+
.get();
|
|
70
|
+
|
|
71
|
+
const user = _.find(users, { provider });
|
|
72
|
+
|
|
73
|
+
if (_.isEmpty(user) && !advancedSettings.allow_register) {
|
|
74
|
+
throw new Error('Register action is actually not available.');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!_.isEmpty(user)) {
|
|
78
|
+
return user;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (users.length > 1 && advancedSettings.unique_email) {
|
|
82
|
+
throw new Error('Email is already taken.');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Retrieve default role.
|
|
86
|
+
const defaultRole = await strapi
|
|
87
|
+
.query('plugin::users-permissions.role')
|
|
88
|
+
.findOne({ where: { type: advancedSettings.default_role } });
|
|
89
|
+
|
|
90
|
+
// Create the new user.
|
|
91
|
+
const newUser = {
|
|
92
|
+
...profile,
|
|
93
|
+
email, // overwrite with lowercased email
|
|
94
|
+
provider,
|
|
95
|
+
role: defaultRole.id,
|
|
96
|
+
confirmed: true,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const createdUser = await strapi
|
|
100
|
+
.query('plugin::users-permissions.user')
|
|
101
|
+
.create({ data: newUser });
|
|
102
|
+
|
|
103
|
+
return createdUser;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const buildRedirectUri = (provider = '') => {
|
|
107
|
+
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
108
|
+
return urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, 'connect', provider, 'callback');
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
connect,
|
|
113
|
+
buildRedirectUri,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
@@ -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 findOne(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 find() {
|
|
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
|
+
});
|