Skip to content

Commit 4393c98

Browse files
add v3.6.11 patches
1 parent 171587e commit 4393c98

File tree

3 files changed

+251
-0
lines changed

3 files changed

+251
-0
lines changed

3.6.11/gitkeep

Whitespace-only changes.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
diff --git a/node_modules/strapi-plugin-email/services/Email.js b/node_modules/strapi-plugin-email/services/Email.js
2+
index 797c17e..5c09913 100644
3+
--- a/node_modules/strapi-plugin-email/services/Email.js
4+
+++ b/node_modules/strapi-plugin-email/services/Email.js
5+
@@ -2,6 +2,17 @@
6+
7+
const _ = require('lodash');
8+
9+
+const keysDeep = (obj, path = []) =>
10+
+ !_.isObject(obj)
11+
+ ? path.join('.')
12+
+ : _.reduce(obj, (acc, next, key) => _.concat(acc, keysDeep(next, [...path, key])), []);
13+
+
14+
+const createStrictInterpolationRegExp = (allowedVariableNames, flags) => {
15+
+ const oneOfVariables = allowedVariableNames.join('|');
16+
+
17+
+ return new RegExp(`<%=\\s*(${oneOfVariables})\\s*%>`, flags);
18+
+};
19+
+
20+
const getProviderSettings = () => {
21+
return strapi.plugins.email.config;
22+
};
23+
@@ -26,10 +37,19 @@ const sendTemplatedEmail = (emailOptions = {}, emailTemplate = {}, data = {}) =>
24+
);
25+
}
26+
27+
+ const allowedInterpolationVariables = keysDeep(data);
28+
+ const interpolate = createStrictInterpolationRegExp(allowedInterpolationVariables, 'g');
29+
+
30+
const templatedAttributes = attributes.reduce(
31+
(compiled, attribute) =>
32+
emailTemplate[attribute]
33+
- ? Object.assign(compiled, { [attribute]: _.template(emailTemplate[attribute])(data) })
34+
+ ? Object.assign(compiled, {
35+
+ [attribute]: _.template(emailTemplate[attribute], {
36+
+ interpolate,
37+
+ evaluate: false,
38+
+ escape: false,
39+
+ })(data),
40+
+ })
41+
: compiled,
42+
{}
43+
);
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
diff --git a/node_modules/strapi-plugin-users-permissions/controllers/validation/email-template.js b/node_modules/strapi-plugin-users-permissions/controllers/validation/email-template.js
2+
index ce455b5..766ec1a 100644
3+
--- a/node_modules/strapi-plugin-users-permissions/controllers/validation/email-template.js
4+
+++ b/node_modules/strapi-plugin-users-permissions/controllers/validation/email-template.js
5+
@@ -1,8 +1,22 @@
6+
'use strict';
7+
8+
-const _ = require('lodash');
9+
+const { trim } = require('lodash/fp');
10+
+
11+
+const createStrictInterpolationRegExp = (allowedVariableNames, flags) => {
12+
+ const oneOfVariables = allowedVariableNames.join('|');
13+
+
14+
+ return new RegExp(`<%=\\s*(${oneOfVariables})\\s*%>`, flags);
15+
+};
16+
+
17+
+const createLooseInterpolationRegExp = (flags) => new RegExp(/<%=([\s\S]+?)%>/, flags);
18+
+
19+
+const invalidPatternsRegexes = [
20+
+ // Ignore "evaluation" patterns: <% ... %>
21+
+ /<%[^=]([\s\S]*?)%>/m,
22+
+ // Ignore basic string interpolations
23+
+ /\${([^{}]*)}/m,
24+
+];
25+
26+
-const invalidPatternsRegexes = [/<%[^=]([^<>%]*)%>/m, /\${([^{}]*)}/m];
27+
const authorizedKeys = ['URL', 'CODE', 'USER', 'USER.email', 'USER.username', 'TOKEN'];
28+
29+
const matchAll = (pattern, src) => {
30+
@@ -13,7 +27,7 @@ const matchAll = (pattern, src) => {
31+
while ((match = regexPatternWithGlobal.exec(src))) {
32+
const [, group] = match;
33+
34+
- matches.push(_.trim(group));
35+
+ matches.push(trim(group));
36+
}
37+
return matches;
38+
};
39+
@@ -25,11 +39,18 @@ const isValidEmailTemplate = template => {
40+
}
41+
}
42+
43+
- const matches = matchAll(/<%=([^<>%=]*)%>/, template);
44+
- for (const match of matches) {
45+
- if (!authorizedKeys.includes(match)) {
46+
- return false;
47+
- }
48+
+ const interpolation = {
49+
+ // Strict interpolation pattern to match only valid groups
50+
+ strict: createStrictInterpolationRegExp(authorizedKeys),
51+
+ // Weak interpolation pattern to match as many group as possible.
52+
+ loose: createLooseInterpolationRegExp(),
53+
+ };
54+
+
55+
+ const strictMatches = matchAll(interpolation.strict, template);
56+
+ const looseMatches = matchAll(interpolation.loose, template);
57+
+
58+
+ if (looseMatches.length > strictMatches.length) {
59+
+ return false;
60+
}
61+
62+
return true;
63+
diff --git a/node_modules/strapi-plugin-users-permissions/services/User.js b/node_modules/strapi-plugin-users-permissions/services/User.js
64+
index 0ad62ac..8ee2598 100644
65+
--- a/node_modules/strapi-plugin-users-permissions/services/User.js
66+
+++ b/node_modules/strapi-plugin-users-permissions/services/User.js
67+
@@ -11,6 +11,69 @@ const bcrypt = require('bcryptjs');
68+
69+
const { sanitizeEntity, getAbsoluteServerUrl } = require('strapi-utils');
70+
71+
+function normalize (strArray) {
72+
+ const resultArray = [];
73+
+ if (strArray.length === 0) { return ''; }
74+
+
75+
+ if (typeof strArray[0] !== 'string') {
76+
+ throw new TypeError('Url must be a string. Received ' + strArray[0]);
77+
+ }
78+
+
79+
+ // If the first part is a plain protocol, we combine it with the next part.
80+
+ if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
81+
+ strArray[0] = strArray.shift() + strArray[0];
82+
+ }
83+
+
84+
+ // There must be two or three slashes in the file protocol, two slashes in anything else.
85+
+ if (strArray[0].match(/^file:\/\/\//)) {
86+
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
87+
+ } else {
88+
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
89+
+ }
90+
+
91+
+ for (let i = 0; i < strArray.length; i++) {
92+
+ let component = strArray[i];
93+
+
94+
+ if (typeof component !== 'string') {
95+
+ throw new TypeError('Url must be a string. Received ' + component);
96+
+ }
97+
+
98+
+ if (component === '') { continue; }
99+
+
100+
+ if (i > 0) {
101+
+ // Removing the starting slashes for each component but the first.
102+
+ component = component.replace(/^[\/]+/, '');
103+
+ }
104+
+ if (i < strArray.length - 1) {
105+
+ // Removing the ending slashes for each component but the last.
106+
+ component = component.replace(/[\/]+$/, '');
107+
+ } else {
108+
+ // For the last component we will combine multiple slashes to a single one.
109+
+ component = component.replace(/[\/]+$/, '/');
110+
+ }
111+
+
112+
+ resultArray.push(component);
113+
+
114+
+ }
115+
+
116+
+ let str = resultArray.join('/');
117+
+ // Each input component is now separated by a single slash except the possible first plain protocol part.
118+
+
119+
+ // remove trailing slash before parameters or hash
120+
+ str = str.replace(/\/(\?|&|#[^!])/g, '$1');
121+
+
122+
+ // replace ? in parameters with &
123+
+ const parts = str.split('?');
124+
+ str = parts.shift() + (parts.length > 0 ? '?': '') + parts.join('&');
125+
+
126+
+ return str;
127+
+}
128+
+
129+
+function urlJoin(...args) {
130+
+ const parts = Array.from(Array.isArray(args[0]) ? args[0] : args);
131+
+ return normalize(parts);
132+
+}
133+
+
134+
module.exports = {
135+
/**
136+
* Promise to count users
137+
@@ -143,13 +206,24 @@ module.exports = {
138+
139+
await this.edit({ id: user.id }, { confirmationToken });
140+
141+
- settings.message = await userPermissionService.template(settings.message, {
142+
- URL: `${getAbsoluteServerUrl(strapi.config)}/auth/email-confirmation`,
143+
- USER: userInfo,
144+
- CODE: confirmationToken,
145+
- });
146+
-
147+
- settings.object = await userPermissionService.template(settings.object, { USER: userInfo });
148+
+ try {
149+
+ settings.message = await userPermissionService.template(settings.message, {
150+
+ URL: urlJoin(getAbsoluteServerUrl(strapi.config), '/auth/email-confirmation'),
151+
+ SERVER_URL: getAbsoluteServerUrl(strapi.config),
152+
+ ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
153+
+ USER: userInfo,
154+
+ CODE: confirmationToken,
155+
+ });
156+
+
157+
+ settings.object = await userPermissionService.template(settings.object, {
158+
+ USER: userInfo,
159+
+ });
160+
+ } catch {
161+
+ strapi.log.error(
162+
+ '[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'
163+
+ );
164+
+ return;
165+
+ }
166+
167+
// Send an email to the user.
168+
await strapi.plugins['email'].services.email.send({
169+
diff --git a/node_modules/strapi-plugin-users-permissions/services/UsersPermissions.js b/node_modules/strapi-plugin-users-permissions/services/UsersPermissions.js
170+
index 08f97fc..fe6474b 100644
171+
--- a/node_modules/strapi-plugin-users-permissions/services/UsersPermissions.js
172+
+++ b/node_modules/strapi-plugin-users-permissions/services/UsersPermissions.js
173+
@@ -9,6 +9,17 @@ const request = require('request');
174+
* @description: A set of functions similar to controller's actions to avoid code duplication.
175+
*/
176+
177+
+const keysDeep = (obj, path = []) =>
178+
+ !_.isObject(obj)
179+
+ ? path.join('.')
180+
+ : _.reduce(obj, (acc, next, key) => _.concat(acc, keysDeep(next, [...path, key])), []);
181+
+
182+
+const createStrictInterpolationRegExp = (allowedVariableNames, flags) => {
183+
+ const oneOfVariables = allowedVariableNames.join('|');
184+
+
185+
+ return new RegExp(`<%=\\s*(${oneOfVariables})\\s*%>`, flags);
186+
+};
187+
+
188+
const DEFAULT_PERMISSIONS = [
189+
{ action: 'admincallback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
190+
{ action: 'adminregister', controller: 'auth', type: 'users-permissions', roleType: 'public' },
191+
@@ -410,7 +421,15 @@ module.exports = {
192+
},
193+
194+
template(layout, data) {
195+
- const compiledObject = _.template(layout);
196+
- return compiledObject(data);
197+
+ const allowedTemplateVariables = keysDeep(data);
198+
+
199+
+ // Create a strict interpolation RegExp based on possible variable names
200+
+ const interpolate = createStrictInterpolationRegExp(allowedTemplateVariables, 'g');
201+
+
202+
+ try {
203+
+ return _.template(layout, { interpolate, evaluate: false, escape: false })(data);
204+
+ } catch (e) {
205+
+ throw new Error('Invalid email template');
206+
+ }
207+
},
208+
};

0 commit comments

Comments
 (0)