Strapi v4 sanitizeEntity
Asked Answered
A

6

9

I'm trying out the new strapi v4 right now (4.0.0) community edition. I've got a custom controller which queries for the current user and (in the future) fetches related objects.

When I did this with strapi v3 I used the built-in sanititzeEntitiy - helper function to remove sensitive fields from the user instance. In v4 however, this function appears to not exist anymore and I can't figure out how to achieve this.

Is there anyone that can help me with this? My code so far is:

module.exports = {
  currentUser: async(ctx, next) => {
    let user = ctx.state.user;
    // TODO: sanitize this
  }
}

In v3 I just did return sanitizeEntity(user); which would have the desired effect. I just can't figure out how to do this in v4 and I can't find anything related to that in the docs.

Apo answered 6/12, 2021 at 17:32 Comment(1)
What if you edit ./config/api.js and in the exported object add the following: responses: { privateAttributes: ['password', 'another_sensitive_field'] }, would that help?Intertype
A
5

So I simultaneously posted this question on the strapi community forums. A user named JustJerem got me an answer to this question which looks like this:

**const { sanitizeEntity } = require("strapi-utils/lib");**

module.exports = (plugin) => {

  plugin.controllers.user.deleteMe = async (ctx) => {
    const entity = await strapi.entityService.delete('plugin::users-permissions.user', user.id)
    var result = **sanitizeEntity(entity, { model: strapi.getModel('plugin::users-permissions.user') })**
    return result
  };
//...
};

The original answer in the strapi forums can be found here:

https://forum.strapi.io/t/v4-0-0-sanitize-user-data/13326/4?u=derelektrischemoench

All credits to this solution go out to JustJerem on the strapi boards. Doing it like this worked for me. Hopefully this can help someone else, too.

Greetings, derelektrischemoench

Apo answered 7/2, 2022 at 18:57 Comment(1)
Thanks for mentioning my original answer :)Gitt
G
8

You need to use the "sanitize" utility from "@strapi/utils".

const { sanitize } = require('@strapi/utils');

module.exports = createCoreController('api::payment.payment', ({ strapi }) => ({
  async create(ctx) {
    const entity = await strapi.entityService.create('api::payment.payment', {
      data: {
        field1: 1,
        field2: 2,
      },
    });
    const sanitizedEntity = await sanitize.contentAPI.output(entity);

    return { data: sanitizedEntity };
  },
}));

Gumbotil answered 19/12, 2021 at 8:16 Comment(4)
I tried this, but it doesn't change anything, the password fields still isn't removed from the user instance.Apo
My steps were: get the user: let user = await.getService('user').fetch({id}); let userSanitized = await sanititze.contentApi.output(user); return userSanitized Unfortunately this still retains the password field on the user instance.Apo
@Apo In any case, you need to pass the circuitry inside the sanitizer. You can try this method, but make sure you pass the schema as the first parameter. I don't know how to get it with strapi. sanitize.sanitizers.sanitizePasswords(schema, entity)Gumbotil
Hi Dmitry, unfortunately this doesn't work either. I still get the password fields on my user. Is there maybe something I need to change in the model itself in the backend or somehing?Apo
A
5

So I simultaneously posted this question on the strapi community forums. A user named JustJerem got me an answer to this question which looks like this:

**const { sanitizeEntity } = require("strapi-utils/lib");**

module.exports = (plugin) => {

  plugin.controllers.user.deleteMe = async (ctx) => {
    const entity = await strapi.entityService.delete('plugin::users-permissions.user', user.id)
    var result = **sanitizeEntity(entity, { model: strapi.getModel('plugin::users-permissions.user') })**
    return result
  };
//...
};

The original answer in the strapi forums can be found here:

https://forum.strapi.io/t/v4-0-0-sanitize-user-data/13326/4?u=derelektrischemoench

All credits to this solution go out to JustJerem on the strapi boards. Doing it like this worked for me. Hopefully this can help someone else, too.

Greetings, derelektrischemoench

Apo answered 7/2, 2022 at 18:57 Comment(1)
Thanks for mentioning my original answer :)Gitt
E
2

In Strapi v4 it looks like it's replaced by sanitizeOutput function. It accepts the entity but looks like it needs context (ctx) to be passed too. It is not described anywhere in the official documentation though.

Eskimoaleut answered 7/12, 2021 at 16:54 Comment(4)
I'm having a hard time getting this to work. When I try calling sanitizeOutput like so: sanitizeOutput(user, ctx) I'm getting an exception: sanitizeOutput is not defined. My guess is I'm going to have to require it somehow but the only thing related I can find is defaultSanitizeOutput from sanitize.sanitizers which when used returns some object with function declarations which I don't know what to do with.Apo
I don't get what's the scope of this in await this.sanitizeOutput but you can find it here and dig through the documentation or strapi files on how to use it properly.Eskimoaleut
True, the this is obsolete. However, if I use sanitizeOutput like this: const userSanitized = await sanitizeOutput(user, ctx); The sanitization doesn't work, I still get the user's hashed password in the response. How can I change this / what am I doing wrong?Apo
@Apo what I did was ``` delete user.password ``` . But I believe it's not the best solution.Ogrady
A
0

So some time later, JustJerem, a guy on the strapi community forums came up with a solution to this; firstly you have to install strapi-utils: npm i -D strapi-utils, then in your controller you have to do this:

const { sanitizeEntity } = require('strapi-utils/lib');

currentUser: async (ctx, next) => {
    const {id, isAdmin = false} = await strapi.plugins['users-permissions'].services.jwt.getToken(ctx); 
    const entity = await strapi.entityService.findOne('plugin::users-permissions.user', id); // or get the user differently, in this case I can't take it from context

    let sanitizedEntity = sanitizeEntity(entity, { model: strapi.getModel('plugin::users-permissions.user') });
    return sanitizedEntity;
  }

And that's all there is to it. Here's the link to his original post: https://forum.strapi.io/t/v4-0-0-sanitize-user-data/13326

Apo answered 22/1, 2022 at 6:57 Comment(0)
F
0

You can define a sanitizeOutput function and use it (works in strapi 4):

const utils = require("@strapi/utils");
const {sanitize} = utils;

const sanitizeOutput = (data, ctx) => {
   const schema = strapi.getModel('plugin::xxx.yyy');
   const {auth} = ctx.state;
   return sanitize.contentAPI.output(data, schema, {auth});
};

module.exports = {

     async find(ctx) {
       let entities = ... //retrieve entities
       //call the function
       ctx.body = await sanitizeOutput(entities, ctx);

     },
};
Fatling answered 15/4, 2022 at 13:41 Comment(1)
Do you know what {auth} is for in this line? return sanitize.contentAPI.output(data, schema, {auth}); I'm currently customizing the callback function of Strapi's auth controller to populate some fields, and the client only receives these fields when I remove {auth} from said line.Ofori
F
0

you can check this doc strapi

const { sanitize } = require("@strapi/utils");

      const contentType = strapi.contentType("plugin::users-permissions.user");
  const sanitizedBody = await sanitize.contentAPI.output(
    ctx.request.body,
    contentType,
    {
      auth: ctx.state.auth,
    }
  );
Flicker answered 14/2, 2024 at 12:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.