How to evaluate string encoded conditions from an API call? #185
-
We are currently exploring the use of fromvulate in an application where the schemas should be generated in independent backend. We are now facing one issue related to conditional display of fields: The API provides the conditions as strings and they are not evaluated: const SCHEMA = [
{
model: 'size_specification',
component: 'FormSelect',
label: 'How would you like to enter the size of the system?',
required: true,
options: ['By Power rating (kWp)', 'By area (m2)'],
},
{
model: 'power_rating',
component: 'FormFloat',
label: 'What is the power rating of the system?',
condition: "(model) => model.size_specification === 'By Power rating (kWp)'",
},
{
model: 'area',
component: 'FormInteger',
label: 'What is the size of the system?',
condition: "(model) => model.size_specification === 'By area (m2)'",
},
] To enable evaluation we convert the string into a function which is then interpreted: ...
const model= ref({})
useSchemaForm(model)
const schema = computed(() => {
SCHEMA.forEach(function (s) {
if (s.condition) {
// eslint-disable-next-line no-new-func
s.condition = Function(`"use strict";return (${s.condition})`)(model.value)
}
})
return SCHEMA
})
... Our question is now: Is this approach acceptable in terms of security and/or are there better ways while keeping the same flexibility? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
Hey @datenspast that sounds like a cool use case. The Another solution would be for your backend to give you a different way to parse the condition, where maybe it says
Maybe in a later release of FormVueLate we can take into consideration doing some magic schema conditions like this, and would be a great feature to have, but I have to put this on the wishlist for now cause I am a little pressed on time with other things |
Beta Was this translation helpful? Give feedback.
-
I would follow @marina-mosti advice and avoid using The concerns also include sending untranspiled code so if an engineer used new/unsupported syntax in some browsers. Also, it could send malformed functions, either invalid JavaScript functions or functions with their return type that isn't a boolean (common with && and ||). I would recommend going to a harder path where you explicitly define what kind of conditions possible via JSON, for example, I did something like this a while back: {
"model": "area",
"type": "integer",
"label": "What is the size of the system?",
"when": { "field": "size_specification", "eq": "By area (m2)" }
} Or if you are a fan of tuples: {
"model": "area",
"type": "integer",
"label": "What is the size of the system?",
"when": ["size_specification", "By area (m2)"],
} And before you would pass these to formvuelate you would need to transform the condition object expression to a function, which is straight forward: function transformSchemaConditions(schema, model) {
const transform = schema.map(field => {
let condition = undefined;
if (field.when) {
condition = transformCondition(field.when, model);
}
return {
...field,
condition
}
});
}
// assuming you go with tuples
function transformCondition(condition, model) {
return () => model.value[condition[0]] === condition[1];
} With added complexity, you could scale this to include operators like Mongo's API like: The main benefit of this condition schema to me is that it can be type-safe with TypeScript, which might come in handy. Of course, this is quite an investment to implement, and if your current solution works for you, then by all means. This might be a nice plugin for |
Beta Was this translation helpful? Give feedback.
I would follow @marina-mosti advice and avoid using
Function
.The concerns also include sending untranspiled code so if an engineer used new/unsupported syntax in some browsers. Also, it could send malformed functions, either invalid JavaScript functions or functions with their return type that isn't a boolean (common with && and ||).
I would recommend going to a harder path where you explicitly define what kind of conditions possible via JSON, for example, I did something like this a while back:
Or if you are a fan of tuples:
{ "model"