@strapi/plugin-users-permissions 4.6.0-beta.0 → 4.6.0-beta.2
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/pages/Providers/index.js +1 -12
- package/admin/src/translations/dk.json +0 -1
- package/admin/src/translations/en.json +0 -1
- package/admin/src/translations/es.json +0 -1
- package/admin/src/translations/ko.json +0 -1
- package/admin/src/translations/pl.json +0 -1
- package/admin/src/translations/sv.json +0 -1
- package/admin/src/translations/tr.json +38 -1
- package/admin/src/translations/zh.json +0 -1
- package/package.json +5 -5
- package/server/controllers/validation/email-template.js +32 -8
- package/server/services/user.js +18 -10
- package/server/services/users-permissions.js +15 -2
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from '@strapi/helper-plugin';
|
|
15
15
|
import has from 'lodash/has';
|
|
16
16
|
import upperFirst from 'lodash/upperFirst';
|
|
17
|
-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
18
17
|
import { HeaderLayout, Layout, ContentLayout } from '@strapi/design-system/Layout';
|
|
19
18
|
import { Main } from '@strapi/design-system/Main';
|
|
20
19
|
import { useNotifyAT } from '@strapi/design-system/LiveRegions';
|
|
@@ -163,16 +162,9 @@ export const ProvidersPage = () => {
|
|
|
163
162
|
<LoadingIndicatorPage />
|
|
164
163
|
) : (
|
|
165
164
|
<ContentLayout>
|
|
166
|
-
<Table colCount={
|
|
165
|
+
<Table colCount={3} rowCount={rowCount + 1}>
|
|
167
166
|
<Thead>
|
|
168
167
|
<Tr>
|
|
169
|
-
<Th>
|
|
170
|
-
<Typography variant="sigma" textColor="neutral600">
|
|
171
|
-
<VisuallyHidden>
|
|
172
|
-
{formatMessage({ id: getTrad('Providers.image'), defaultMessage: 'Image' })}
|
|
173
|
-
</VisuallyHidden>
|
|
174
|
-
</Typography>
|
|
175
|
-
</Th>
|
|
176
168
|
<Th>
|
|
177
169
|
<Typography variant="sigma" textColor="neutral600">
|
|
178
170
|
{formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
|
|
@@ -204,9 +196,6 @@ export const ProvidersPage = () => {
|
|
|
204
196
|
condition: canUpdate,
|
|
205
197
|
})}
|
|
206
198
|
>
|
|
207
|
-
<Td width="">
|
|
208
|
-
<FontAwesomeIcon icon={provider.icon} />
|
|
209
|
-
</Td>
|
|
210
199
|
<Td width="45%">
|
|
211
200
|
<Typography fontWeight="semiBold" textColor="neutral800">
|
|
212
201
|
{provider.name}
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "Redigér e-mail skabeloner",
|
|
55
55
|
"PopUpForm.header.edit.providers": "Redigér udbydere",
|
|
56
56
|
"Providers.data.loaded": "Providers hentet",
|
|
57
|
-
"Providers.image": "Billede",
|
|
58
57
|
"Providers.status": "Status",
|
|
59
58
|
"Roles.empty": "Du har endnu ingen roller.",
|
|
60
59
|
"Roles.empty.search": "Ingen roller matcher søgningen.",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "Edit email template",
|
|
55
55
|
"PopUpForm.header.edit.providers": "Edit Provider",
|
|
56
56
|
"Providers.data.loaded": "Providers have been loaded",
|
|
57
|
-
"Providers.image": "Image",
|
|
58
57
|
"Providers.status": "Status",
|
|
59
58
|
"Roles.empty": "You don't have any roles yet.",
|
|
60
59
|
"Roles.empty.search": "No roles match the search.",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "Editar Plantillas de Email",
|
|
55
55
|
"PopUpForm.header.edit.providers": "Editar proveedor",
|
|
56
56
|
"Providers.data.loaded": "Los proveedores se han cargado",
|
|
57
|
-
"Providers.image": "Imagen",
|
|
58
57
|
"Providers.status": "Estado",
|
|
59
58
|
"Roles.empty": "Aún no tienes ningún rol.",
|
|
60
59
|
"Roles.empty.search": "Ningún rol coincide con la búsqueda.",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "이메일 템플릿 수정",
|
|
55
55
|
"PopUpForm.header.edit.providers": "프로바이더 수정",
|
|
56
56
|
"Providers.data.loaded": "프로바이더를 불러왔습니다.",
|
|
57
|
-
"Providers.image": "이미지",
|
|
58
57
|
"Providers.status": "상태",
|
|
59
58
|
"Roles.empty": "아직 역할이 없습니다.",
|
|
60
59
|
"Roles.empty.search": "검색과 일치하는 역할이 없습니다.",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "Zmień szablony e-mail",
|
|
55
55
|
"PopUpForm.header.edit.providers": "Edytuj dostawcę",
|
|
56
56
|
"Providers.data.loaded": "Dostawcy zostali załadowani",
|
|
57
|
-
"Providers.image": "Obrazek",
|
|
58
57
|
"Providers.status": "Status",
|
|
59
58
|
"Roles.empty": "Nie masz jeszcze żadnych ról.",
|
|
60
59
|
"Roles.empty.search": "Żadne role nie pasują do wyszukiwania.",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "Redigera e-postmallar",
|
|
55
55
|
"PopUpForm.header.edit.providers": "Redigera tjänst",
|
|
56
56
|
"Providers.data.loaded": "Tjänster har laddats in",
|
|
57
|
-
"Providers.image": "Bild",
|
|
58
57
|
"Providers.status": "Status",
|
|
59
58
|
"Roles.empty": "Du har inga roller än.",
|
|
60
59
|
"Roles.empty.search": "Inga roller matchar sökningen.",
|
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
"EditForm.inputToggle.label.email-confirmation": "E-posta onayını etkinleştir",
|
|
11
11
|
"EditForm.inputToggle.label.email-confirmation-redirection": "Yönlendirme URL'si",
|
|
12
12
|
"EditForm.inputToggle.label.sign-up": "Kayıtları etkinleştir",
|
|
13
|
+
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ör: https://yourfrontend.com/email-confirmation-redirection",
|
|
14
|
+
"EditForm.inputToggle.placeholder.email-reset-password": "ör: https://yourfrontend.com/reset-password",
|
|
15
|
+
"EditPage.form.roles": "Rol detayları",
|
|
16
|
+
"Email.template.data.loaded": "E-posta şablonları yüklendi",
|
|
17
|
+
"Email.template.email_confirmation": "E-posta adresi doğrulaması",
|
|
18
|
+
"Email.template.form.edit.label": "Şablonu düzenle",
|
|
19
|
+
"Email.template.table.action.label": "eylem",
|
|
20
|
+
"Email.template.table.icon.label": "ikon",
|
|
21
|
+
"Email.template.table.name.label": "ad",
|
|
22
|
+
"Form.advancedSettings.data.loaded": "Gelişmiş ayarlar verisi yüklendi",
|
|
13
23
|
"HeaderNav.link.advancedSettings": "Gelişmiş Ayarlar",
|
|
14
24
|
"HeaderNav.link.emailTemplates": "E-posta Şablonları",
|
|
15
25
|
"HeaderNav.link.providers": "Sağlayıcıları",
|
|
@@ -19,12 +29,14 @@
|
|
|
19
29
|
"Policies.header.hint": "Uygulamanın eylemlerini veya eklentinin eylemlerini seçin ve bağlı rotayı görüntülemek için dişli çark simgesini tıklayın",
|
|
20
30
|
"Policies.header.title": "Gelişmiş Ayarlar",
|
|
21
31
|
"PopUpForm.Email.email_templates.inputDescription": "Değişkenleri nasıl kullanacağınızdan emin değilseniz, {link}",
|
|
32
|
+
"PopUpForm.Email.link.documentation": "dokümantasyonu kontrol et.",
|
|
22
33
|
"PopUpForm.Email.options.from.email.label": "Gönderenin E-posta",
|
|
23
34
|
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
|
|
24
35
|
"PopUpForm.Email.options.from.name.label": "Gönderenin adı",
|
|
25
36
|
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
|
|
26
37
|
"PopUpForm.Email.options.message.label": "Mesaj",
|
|
27
38
|
"PopUpForm.Email.options.object.label": "Konu",
|
|
39
|
+
"PopUpForm.Email.options.object.placeholder": "%APP_NAME% için e-posta adresini doğrula",
|
|
28
40
|
"PopUpForm.Email.options.response_email.label": "Yanıt e-postası",
|
|
29
41
|
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
|
|
30
42
|
"PopUpForm.Providers.enabled.description": "Devre dışı bırakıldıysa kullanıcılar bu sağlayıcıyı kullanamaz.",
|
|
@@ -32,13 +44,38 @@
|
|
|
32
44
|
"PopUpForm.Providers.key.label": "Web istemcisi ID",
|
|
33
45
|
"PopUpForm.Providers.key.placeholder": "METİN",
|
|
34
46
|
"PopUpForm.Providers.redirectURL.front-end.label": "Arayüz uygulamanızın yönlendirme URL'si",
|
|
47
|
+
"PopUpForm.Providers.redirectURL.label": "{provider} uygulama ayarlarına ekleyeceğin yönlendirme URLi",
|
|
35
48
|
"PopUpForm.Providers.secret.label": "Web istemcisi Secret",
|
|
36
49
|
"PopUpForm.Providers.secret.placeholder": "METİN",
|
|
37
50
|
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
|
|
38
51
|
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
|
|
39
52
|
"PopUpForm.header.edit.email-templates": "E-posta Şablonlarını Düzenle",
|
|
53
|
+
"PopUpForm.header.edit.providers": "Sağlayıcıyı Düzenle",
|
|
54
|
+
"Providers.data.loaded": "Sağlayıcılar yüklendi",
|
|
55
|
+
"Providers.image": "Görsel",
|
|
56
|
+
"Providers.status": "Durum",
|
|
57
|
+
"Roles.empty": "Henüz hiç rolün yok.",
|
|
58
|
+
"Roles.empty.search": "Aramaya uygun rol bulunmadı.",
|
|
59
|
+
"Settings.roles.deleted": "Rol silindi",
|
|
60
|
+
"Settings.roles.edited": "Rol düzenlendi",
|
|
61
|
+
"Settings.section-label": "Kullanıcılar ve İzinler eklentisi",
|
|
62
|
+
"components.Input.error.validation.email": "Bu geçersiz bir e-posta",
|
|
63
|
+
"components.Input.error.validation.json": "Bu JSON biçimine uymuyor",
|
|
64
|
+
"components.Input.error.validation.max": "Değer çok yüksek.",
|
|
65
|
+
"components.Input.error.validation.maxLength": "Değer çok uzun.",
|
|
66
|
+
"components.Input.error.validation.min": "Değer çok düşük.",
|
|
67
|
+
"components.Input.error.validation.minLength": "Değer çok kısa.",
|
|
68
|
+
"components.Input.error.validation.minSupMax": "Üst olamaz",
|
|
69
|
+
"components.Input.error.validation.regex": "Değer RegExp'e uymuyor.",
|
|
70
|
+
"components.Input.error.validation.required": "Değer gerekli.",
|
|
71
|
+
"components.Input.error.validation.unique": "Değer zaten kullanılıyor.",
|
|
40
72
|
"notification.success.submit": "Ayarlar güncellendi",
|
|
73
|
+
"page.title": "Ayarlar - Roller",
|
|
41
74
|
"plugin.description.long": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun. Bu eklenti, kullanıcı grupları arasındaki izinleri yönetmenize izin veren bir ACL stratejisiyle de gelir.",
|
|
42
75
|
"plugin.description.short": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun",
|
|
43
|
-
"plugin.name": "Roller
|
|
76
|
+
"plugin.name": "Roller ve İzinler",
|
|
77
|
+
"popUpWarning.button.cancel": "İptal Et",
|
|
78
|
+
"popUpWarning.button.confirm": "Onayla",
|
|
79
|
+
"popUpWarning.title": "Lütfen onayla",
|
|
80
|
+
"popUpWarning.warning.cancel": "Değişiklikleri iptal etmek istediğinden emin misin?"
|
|
44
81
|
}
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"PopUpForm.header.edit.email-templates": "編輯郵件範本",
|
|
55
55
|
"PopUpForm.header.edit.providers": "編輯供應者",
|
|
56
56
|
"Providers.data.loaded": "已載入供應者",
|
|
57
|
-
"Providers.image": "圖片",
|
|
58
57
|
"Providers.status": "狀態",
|
|
59
58
|
"Roles.empty": "您目前沒有任何角色。",
|
|
60
59
|
"Roles.empty.search": "沒有符合搜尋的角色。",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-users-permissions",
|
|
3
|
-
"version": "4.6.0-beta.
|
|
3
|
+
"version": "4.6.0-beta.2",
|
|
4
4
|
"description": "Protect your API with a full-authentication process based on JWT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@strapi/helper-plugin": "4.6.0-beta.
|
|
31
|
-
"@strapi/utils": "4.6.0-beta.
|
|
30
|
+
"@strapi/helper-plugin": "4.6.0-beta.2",
|
|
31
|
+
"@strapi/utils": "4.6.0-beta.2",
|
|
32
32
|
"bcryptjs": "2.4.3",
|
|
33
33
|
"grant-koa": "5.4.8",
|
|
34
|
-
"jsonwebtoken": "
|
|
34
|
+
"jsonwebtoken": "9.0.0",
|
|
35
35
|
"koa": "^2.13.4",
|
|
36
36
|
"koa2-ratelimit": "^1.1.2",
|
|
37
37
|
"lodash": "4.17.21",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"required": true,
|
|
65
65
|
"kind": "plugin"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "b852090f931cd21868c4016f24db2f9fdfc7a7ab"
|
|
68
68
|
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { trim } = require('lodash/fp');
|
|
4
|
+
const {
|
|
5
|
+
template: { createLooseInterpolationRegExp, createStrictInterpolationRegExp },
|
|
6
|
+
} = require('@strapi/utils');
|
|
7
|
+
|
|
8
|
+
const invalidPatternsRegexes = [
|
|
9
|
+
// Ignore "evaluation" patterns: <% ... %>
|
|
10
|
+
/<%[^=]([\s\S]*?)%>/m,
|
|
11
|
+
// Ignore basic string interpolations
|
|
12
|
+
/\${([^{}]*)}/m,
|
|
13
|
+
];
|
|
4
14
|
|
|
5
|
-
const invalidPatternsRegexes = [/<%[^=]([^<>%]*)%>/m, /\${([^{}]*)}/m];
|
|
6
15
|
const authorizedKeys = [
|
|
7
16
|
'URL',
|
|
8
17
|
'ADMIN_URL',
|
|
@@ -19,27 +28,42 @@ const matchAll = (pattern, src) => {
|
|
|
19
28
|
let match;
|
|
20
29
|
|
|
21
30
|
const regexPatternWithGlobal = RegExp(pattern, 'g');
|
|
31
|
+
|
|
22
32
|
// eslint-disable-next-line no-cond-assign
|
|
23
33
|
while ((match = regexPatternWithGlobal.exec(src))) {
|
|
24
34
|
const [, group] = match;
|
|
25
35
|
|
|
26
|
-
matches.push(
|
|
36
|
+
matches.push(trim(group));
|
|
27
37
|
}
|
|
38
|
+
|
|
28
39
|
return matches;
|
|
29
40
|
};
|
|
30
41
|
|
|
31
42
|
const isValidEmailTemplate = (template) => {
|
|
43
|
+
// Check for known invalid patterns
|
|
32
44
|
for (const reg of invalidPatternsRegexes) {
|
|
33
45
|
if (reg.test(template)) {
|
|
34
46
|
return false;
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
const interpolation = {
|
|
51
|
+
// Strict interpolation pattern to match only valid groups
|
|
52
|
+
strict: createStrictInterpolationRegExp(authorizedKeys),
|
|
53
|
+
// Weak interpolation pattern to match as many group as possible.
|
|
54
|
+
loose: createLooseInterpolationRegExp(),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Compute both strict & loose matches
|
|
58
|
+
const strictMatches = matchAll(interpolation.strict, template);
|
|
59
|
+
const looseMatches = matchAll(interpolation.loose, template);
|
|
60
|
+
|
|
61
|
+
// If we have more matches with the loose RegExp than with the strict one,
|
|
62
|
+
// then it means that at least one of the interpolation group is invalid
|
|
63
|
+
// Note: In the future, if we wanted to give more details for error formatting
|
|
64
|
+
// purposes, we could return the difference between the two arrays
|
|
65
|
+
if (looseMatches.length > strictMatches.length) {
|
|
66
|
+
return false;
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
return true;
|
package/server/services/user.js
CHANGED
|
@@ -109,17 +109,25 @@ module.exports = ({ strapi }) => ({
|
|
|
109
109
|
await this.edit(user.id, { confirmationToken });
|
|
110
110
|
|
|
111
111
|
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
112
|
-
settings.message = await userPermissionService.template(settings.message, {
|
|
113
|
-
URL: urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, '/auth/email-confirmation'),
|
|
114
|
-
SERVER_URL: getAbsoluteServerUrl(strapi.config),
|
|
115
|
-
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
|
|
116
|
-
USER: sanitizedUserInfo,
|
|
117
|
-
CODE: confirmationToken,
|
|
118
|
-
});
|
|
119
112
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
try {
|
|
114
|
+
settings.message = await userPermissionService.template(settings.message, {
|
|
115
|
+
URL: urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, '/auth/email-confirmation'),
|
|
116
|
+
SERVER_URL: getAbsoluteServerUrl(strapi.config),
|
|
117
|
+
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
|
|
118
|
+
USER: sanitizedUserInfo,
|
|
119
|
+
CODE: confirmationToken,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
settings.object = await userPermissionService.template(settings.object, {
|
|
123
|
+
USER: sanitizedUserInfo,
|
|
124
|
+
});
|
|
125
|
+
} catch {
|
|
126
|
+
strapi.log.error(
|
|
127
|
+
'[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for "user confirmation email". Please make sure your email template is valid and does not contain invalid characters or patterns'
|
|
128
|
+
);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
123
131
|
|
|
124
132
|
// Send an email to the user.
|
|
125
133
|
await strapi
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const { filter, map, pipe, prop } = require('lodash/fp');
|
|
5
5
|
const urlJoin = require('url-join');
|
|
6
|
+
const {
|
|
7
|
+
template: { createStrictInterpolationRegExp },
|
|
8
|
+
errors,
|
|
9
|
+
keysDeep,
|
|
10
|
+
} = require('@strapi/utils');
|
|
6
11
|
|
|
7
12
|
const { getService } = require('../utils');
|
|
8
13
|
|
|
@@ -230,7 +235,15 @@ module.exports = ({ strapi }) => ({
|
|
|
230
235
|
},
|
|
231
236
|
|
|
232
237
|
template(layout, data) {
|
|
233
|
-
const
|
|
234
|
-
|
|
238
|
+
const allowedTemplateVariables = keysDeep(data);
|
|
239
|
+
|
|
240
|
+
// Create a strict interpolation RegExp based on possible variable names
|
|
241
|
+
const interpolate = createStrictInterpolationRegExp(allowedTemplateVariables, 'g');
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
return _.template(layout, { interpolate, evaluate: false, escape: false })(data);
|
|
245
|
+
} catch (e) {
|
|
246
|
+
throw new errors.ApplicationError('Invalid email template');
|
|
247
|
+
}
|
|
235
248
|
},
|
|
236
249
|
});
|