joi icon indicating copy to clipboard operation
joi copied to clipboard

Is it possible to use external parameters in an extension?

Open shanetorres opened this issue 2 years ago • 1 comments

Context

  • node version: 14.x (aws lambda function)
  • module version: 17.4.2
  • environment (e.g. node, browser, native): node in aws lambda
  • used with (e.g. hapi application, another framework, standalone, ...): standalone
  • any other relevant information:

How can we help?

I'm curious if this is something I can do in JOI, but basically I have a user that is sending a request to an API to store a specific type of metric data. Certain metrics however are user role restricted, so I want to be able to use JOI to 1) validate the user is trying to store a valid metric and 2) validate that the user has the proper role to store that metric.

I've tried using context and passing that into the extended validator but I've had no luck in getting that to work, this is ideally what I'd like to be able to do:

From main function:

let userMetric = {id: "metric1", label: "Metric 1"};
let userRoles = ["metric2access"];
const { error, val } = schema.validate({ metric: userMetric }, {context: {userRoles: userRoles }});

Schema:

const Joi = require('./customjoi')

let validMetricIds = ["metric1", "metric2"]

const schema = Joi.object().keys({
    metric: Joi.object({
        id: Joi.string().roleCheck({userRoles: '$userRoles'}).valid(...validMetricIds)
    })
})

customjoi.js

module.exports = Joi.extend((joi) => ({
    type: "string",
    base: joi.string(),
    messages: {
       "string.roleCheck": "User does not have access to {{#label}}"
    },
    rules: {
        roleCheck: {
            params: {
                options: Joi.object({
                    userRoles: Joi.any()
                })
            },
            validate(params, value, helpers) {
                let metricsRequiredRoles = {"metric1": ["metric1access"], "metric2": ["metric2access"]};
                if (Object.keys(metricsRequiredRoles).includes(value)) {
                    requiredRole = metricsRequiredRoles[value];
                    if (params.options.userRoles.includes(requiredRole)) {
                        return value;
                    } else {
                        return helpers.error("string.roleCheck")
                    }
                }

                return value;
            }
        } 
    } 
}))

Is this type of thing possible with JOI? Is there another way to do it that's not like the way I wrote here? I need to be able to reference the user's current roles while validating.

shanetorres avatar Aug 11 '22 17:08 shanetorres

The main problem I see with your snippet is that you're using valid, it acts as a bypass for other rules, anything that matches will prevent other rules from being run, as you explicitly stated those values are valid.

Marsup avatar Oct 11 '22 09:10 Marsup