@strapi/plugin-users-permissions 4.5.4 → 4.5.6

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.
@@ -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={4} rowCount={rowCount + 1}>
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.",
@@ -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.5.4",
3
+ "version": "4.5.6",
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.5.4",
31
- "@strapi/utils": "4.5.4",
30
+ "@strapi/helper-plugin": "4.5.6",
31
+ "@strapi/utils": "4.5.6",
32
32
  "bcryptjs": "2.4.3",
33
33
  "grant-koa": "5.4.8",
34
- "jsonwebtoken": "^8.1.0",
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": "8716ecc920130db5341b0904cf868c6e6b581a5d"
67
+ "gitHead": "d36609ff26fb4e00a41a7e2b657f16c7466203fe"
68
68
  }
@@ -1,8 +1,17 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
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(_.trim(group));
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 matches = matchAll(/<%=([^<>%=]*)%>/, template);
39
- for (const match of matches) {
40
- if (!authorizedKeys.includes(match)) {
41
- return false;
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;
@@ -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
- settings.object = await userPermissionService.template(settings.object, {
121
- USER: sanitizedUserInfo,
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 compiledObject = _.template(layout);
234
- return compiledObject(data);
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
  });