DomDew / strapi-plugin-fuzzy-search

Register a weighted fuzzy search endpoint for Strapi Headless CMS you can add your content types to in no time

Home Page:https://www.npmjs.com/package/strapi-plugin-fuzzy-search

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Results ignore policies?

foxjordan opened this issue · comments

I have policies in place that prevent users from accessing content unless their profiles have associated attributes. The results ignore these policies and return data that shouldn't be accessible. Am I missing a config setting that would ensure it follows the same rules or this that just a limitation?

Hey @foxjordan,
this is in fact a limitation at the moment and a bit of an oversight on my end. I think this would make for an important feature though that needs to be added.

Just off the top of my head I'd say this could be implemented by passing the policies to the search route through the config. Would something like that work for your usecase?

@DomDew I can certainly give it a shot. Would that be in the queryConstraints?

@foxjordan I tried finding a way to implement a feature where policies and middlewares can be passed to the plugin via the config.
Sadly this didn't work for the standard Rest-Api (whilst, oddly enough, it works with GraphQl), as the routes are being registered by Strapi prior to me being able to hook into the users config.

I suggest that for the time being you extend the plugin with your own route and pass whichever policies you need to the routes config. The handler you would need to target would be searchController.search.

Hope this helps. I will leave this Issue up in the hopes that someone can come up with a more convenient solution - though I think that this would be the official way to achieve what you are after.

@DomDew Thanks! I'll try this today and see if there are any issues.

Ok, well I'm sure it's probably possible, but I can't figure it out. My existing policy doesn't seem to affect the results, and I don't understand the extension well enough to write a new custom policy for it. I'll just hold out for a future update or for someone smarter to come along and tell me what I'm doing wrong.

module.exports = async (policyContext, config, { strapi }) => {
console.log("fire access-level policy")
  const id = policyContext.state.user.id;
  const { params } = policyContext
  const art = await strapi.entityService.findOne('api::article.article', params.id, {
    populate: ['user_permissions']
  })
  let art_list = []
  for (let i of art?.user_permissions) {
    art_list.push(i.name)
  }
  if (art_list == null || art_list == []) {
    return false
  }
  const perms = await strapi.entityService.findOne('plugin::users-permissions.user', id, {
    populate: ['user_permission']
  })
  const accessCheck = async () => {
    if (art_list == null || art_list == [] || art_list == "") {
      return "403"
    }
    if (art_list.includes(perms.user_permission.name) ){
      art_list = []
      return true
    }
   return false
  }
  return accessCheck()

};

Strapi allows you to hook into, and overwrite, certain aspects of a plugin that you have installed. As far as I'm seeing you'd have to extend the plugin, by registering a route.

Somewhat like this:

// path: ./src/extensions/strapi-plugin-fuzzy-search/strapi-server.js

module.exports = (plugin) => {
  // If you policy strictly needs to be in the scope of the plugin do something like this first:
  // plugin.policies[newPolicy] = (ctx) => { 
     // whatever 
  //};

  plugin.routes['content-api'].routes.push({
    method: 'GET',
    path: '/your-path',
    handler: 'searchController.search',
    config: {
        policies: ["yourPolicy"]
    }    
  });

  return plugin;
};

At a quick glance at your code though, I think what you are trying to achieve (seeing if a user has the permission to view an article) wouldn't be possible through a policy, as the policy will be applied to the request before it reaches the controller, so before the plugin returns hits for the search. I don't think I will be able to accommodate for something like what you are trying to do (if I understand correctly), namely modifying what the controller returns based on values returned for a given model, as I can't know about the structure of the specific model (which can be anything). I may, of course, be wrong 😅 .

Just on a side note - and I hope you don't mind - I think I'm spotting some issues with your policy just on the plain code level:

  • art_list == [] will always evaluate to false, as when you are testing a condition against an array, js will always make a check against the reference of the array in memory. Meaning that even [] === [] will evaluate to false as these are two different empty arrays. If you want to check whether an array is empty, you would have to check against the length of the array. E.g. if an array has no entries, !yourArray.length would evaluate to true.
  • Generally I would avoid a simple equality check and always use a strict equality check === to prevent weird issues with type conversions during the comparison that can lead to unexpected behaviour.
  • As a result you could shorten this check art_list == null || art_list == [] || art_list == "" to !art_list || !art_list.length. This will check if art_list is falsy (meaning null, undefined, "", 0 and the like) or if the array is empty.
  • Most importantly: You are declaring accessCheck() as an async function, meaning that it will return a promise that will have to be resolved. I don't now Strapis policies well enough to say whether Strapi will resolve this promise for your, but just at face value just calling accessCheck() will be truthy, as promises are (yeah... I know...). You can work with the expected return value by awaiting the return await accessCheck().

Sorry I can't really help aside from some comments... If I understand correctly what you want to achieve with your policy I'd rather use the approach of blocking access to the endpoint through the roles and permissions tab in strapi (so some roles for example dont have access to the search endpoint) or setting up some relation between users and articles, where you only return data for users which are related to an article. You could make use of the queryConstraints key in the config to achieve something like that.

@DomDew I definitely don't mind. Thank you for the notes. The policy as it is works for preventing users from seeing articles they shouldn't have access to, but it was thrown together in a bit of a messy way. I'll definitely use your feedback to clean that up.

As for the search, my policy at least prevents users from opening articles they shouldn't see. I'll have to look at reworking the model a bit I suppose to prevent the search results from displaying them at all.