Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only email and username user attributes are allowed in users-permissions email templates #19442

Closed
mikaelpopowicz opened this issue Feb 7, 2024 · 2 comments
Labels
issue: feature request Issue suggesting a new feature

Comments

@mikaelpopowicz
Copy link

Bug report

Required System information

  • Node.js version: v20.0.9
  • NPM version: 10.1.0
  • Strapi version: 4.19.1
  • Database: sqlite
  • Operating system: Macos
  • Is your project Javascript or Typescript: Javascript

Describe the bug

When using the plugin users-permissions to update one the provided email templates we cannot use custom fields from the user schema.

Indeed we can see that the authorized keys only contain USER.email and USER.username.

Steps to reproduce the behavior

  1. Go to Settings
  2. Go to Email templates
  3. Click on one of the email templates (Reset password or Email address confirmation)
  4. Fill the Message field with <%= USER.firstName %> (or any other configured field in the User content type)
  5. See error Invalid template

Expected behavior

Actually I guess this is the expected behavior but we may want to be able to use any field from user schema.

Mitigating the issue

We can override this behavior to be able to use any field from user schema.

Create a file ./src/extensions/users-permissions/overrides.js which is a copy of the original function where we use our custom email validation

'use strict';

const _ = require("lodash");
// Addition : use our custom validation
const { isValidEmailTemplate } = require("./email-template");

module.exports = {
  async updateEmailTemplate(ctx) {
    if (_.isEmpty(ctx.request.body)) {
      throw new ValidationError('Request body cannot be empty');
    }

    const emailTemplates = ctx.request.body['email-templates'];

    for (const key of Object.keys(emailTemplates)) {
      const template = emailTemplates[key].options.message;

      if (!isValidEmailTemplate(template)) {
        throw new ValidationError('Invalid template');
      }
    }

    await strapi
      .store({type: 'plugin', name: 'users-permissions', key: 'email'})
      .set({value: emailTemplates});

    ctx.send({ok: true});
  }
}

Create a file ./src/extensions/users-permissions/email-template.js which is a copy of the original rule where we change the authorizedKeys array

'use strict';

const { trim } = require('lodash/fp');
const {
  template: { createLooseInterpolationRegExp, createStrictInterpolationRegExp },
} = require('@strapi/utils');

const invalidPatternsRegexes = [
  // Ignore "evaluation" patterns: <% ... %>
  /<%[^=]([\s\S]*?)%>/m,
  // Ignore basic string interpolations
  /\${([^{}]*)}/m,
];

// Addition : get the user schema
const userSchema = strapi.getModel('plugin::users-permissions.user');

const authorizedKeys = [
  'URL',
  'ADMIN_URL',
  'SERVER_URL',
  'CODE',
  'USER',
  // Addition : spread user attributes
  ...Object.entries(userSchema.attributes).map(([key, value]) => `USER.${key}`),
  'TOKEN',
];

const matchAll = (pattern, src) => {
  const matches = [];
  let match;

  const regexPatternWithGlobal = RegExp(pattern, 'g');

  // eslint-disable-next-line no-cond-assign
  while ((match = regexPatternWithGlobal.exec(src))) {
    const [, group] = match;

    matches.push(trim(group));
  }

  return matches;
};

const isValidEmailTemplate = (template) => {
  // Check for known invalid patterns
  for (const reg of invalidPatternsRegexes) {
    if (reg.test(template)) {
      return false;
    }
  }

  const interpolation = {
    // Strict interpolation pattern to match only valid groups
    strict: createStrictInterpolationRegExp(authorizedKeys),
    // Weak interpolation pattern to match as many group as possible.
    loose: createLooseInterpolationRegExp(),
  };

  // Compute both strict & loose matches
  const strictMatches = matchAll(interpolation.strict, template);
  const looseMatches = matchAll(interpolation.loose, template);

  // If we have more matches with the loose RegExp than with the strict one,
  // then it means that at least one of the interpolation group is invalid
  // Note: In the future, if we wanted to give more details for error formatting
  // purposes, we could return the difference between the two arrays
  if (looseMatches.length > strictMatches.length) {
    return false;
  }

  return true;
};

module.exports = {
  isValidEmailTemplate,
};

Now we can override the controller function in ./src/index.js

'use strict';

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register({ strapi }) {
    strapi.controllers['plugin::users-permissions.settings'].updateEmailTemplate = require('./extensions/users-permissions/overrides').updateEmailTemplate;
  },

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap(/*{ strapi }*/) {},
};
@strapi-bot
Copy link

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/email-template-variables-lodash/4233/14

@derrickmehaffy derrickmehaffy added the issue: feature request Issue suggesting a new feature label Feb 9, 2024
Copy link
Contributor

github-actions bot commented Feb 9, 2024

This is a templated message

Hello @mikaelpopowicz,

First thank you for reporting this feature need.
To manage feature requests and the Strapi roadmap, we are using Canny.
You will be able to access the Public Roadmap here: https://feedback.strapi.io.

In your message, please mention the URL of this thread in case some messages are posted there. But the most important is to have your feedback posted on our feedback/roadmap site.
The product team is reading EVERY comment, that really helps us to develop the project in the right direction. We are keeping all feature requests and project insights in one place, our feedback website.

In order to keep our GitHub issues clean and for valid bug reports this issue will be marked as closed, but please feel free to continue the discussion with other community members here.

Thank you for your insight and have a good day.

@github-actions github-actions bot closed this as completed Feb 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue: feature request Issue suggesting a new feature
Projects
Archived in project
Development

No branches or pull requests

3 participants