How to store functions in database for this use-case?

fuzzybabybunny

Moderator<br>Digital & Video Cameras
Moderator
Jan 2, 2006
10,455
35
91
Say that I have a business that represents users who spend a certain amount of time to produce certain quantities of stuff. I want each user to be free to create their own algorithm, or formula, for determining the price that they charge for their work:

Users Collection, with possibly thousands of different users. I'm using MongoDB.


Code:
    {
      userId: 'sdf23d23dwew',
      price: function(time, qty){
        // some algorithm
      }
    },
    {
      userId: '23f5gf34f',
      price: function(time, qty){
        // another algorithm
      }
    },
    {
      userId: '7u76565',
      price: function(time, qty){
        // yet another algorithm
      }
    },
    {
      userId: 'w45y65yh4',
      price: function(time, qty){
        // something else
      }
    }

    //and on and on and on...

Now, JSON doesn't support functions and neither does MongoDB. BUT this use-case of possibly thousands of users, each with the freedom to create their own unique method of determining their own prices, seems to me like being able to store functions inside of their user document would be ideal.

I certainly don't feel like it's a good idea to just store all these thousands of functions in a JS file on the server that somehow gets referenced by a userId when it's needed...

Is there a solution for this case?
 

purbeast0

No Lifer
Sep 13, 2001
53,538
6,365
126
i've worked on stuff like this before where the admin can create custom logic that is used to generate queries based on the forms they built for the users to search with. it is quite a bit more complex than just storing a function like you're hoping.

we use mustache and have the admin generate the fields they want to users to fill out to query on, then they generate mustache templates which reference the fields.

then when the user goes to query, they enter terms into the fields, then the values from the fields are plugged into the mustache template, and mustache is used to generate the query string that is submitted.

we're doing a lot of other stuff under the hood with the data however that is the simplified version. all that is stored in the db while the admin builds the form is the list of fields and the mustache template.
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,613
4,532
75
Well, I'm not sure how to solve the storage problem, but this looks like a security nightmare! Allowing any given user to provide a random script to other users? You just can't do that with raw JavaScript. The script could serve the user a malicious iframe, or redirect, or probably many other things I haven't thought of.

Here are some suggestions on expression evaluators that don't support the full library of JavaScript functions: https://stackoverflow.com/questions/5066824/safe-evaluation-of-arithmetic-expressions-in-javascript

If that works, all you need to store is a short string.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
I fail to see why storage is a problem...? User enters Javascript or whatever other script, you encode it as Base64 and store it as a string. Easy peasy lemon squeezy.

But, like Ken_g6 said, my sphincter puckers a bit at the idea of letting a user write and run arbitrary scripts...
 

Cogman

Lifer
Sep 19, 2000
10,284
138
106
DO NOT DO THIS!

Seriously, just don't do this.

It is a bad idea for a few reasons.

First off, you are exposing yourself to all sorts of nasty attacks. If the code runs server side, you are exposing all of your user data and information to the outside world (including things like passwords!). If the code runs client side, you are one step away from a malicious link which totally hoses your users.

So from a security stand point, this is a really bad idea.

But from a usability standpoint, this is also a bad idea. Expecting your users to write functionality for your website means that you are expecting your users to know how to write code. Further, you are expecting them to write it well. If you decide to abstract away the code writing portion, then why store the code and not just the abstraction? If you are expecting them to write it well then be prepared to diagnose every single problem that arises from any sort of problem. Further, be prepared to support whatever API you introduce to your users for the next eternity. Any bit of functionality you expose to them, whether on purpose or accident, will be used and complaints filed if it goes away.

At my work, I maintain an app that gives trusted internal users the ability to execute arbitrary groovy scripts at various points of the process. The biggest mistake we made is that we didn't sandbox the groovy scripts at all. We exposed our very deep object model to the script writers and now we have a pretty poorly designed API that is really hard to evolve because our stored functionality might break. The process of refactoring is 100x harder because we have to also query against the database to hopefully find out what is using what (And we still miss it in many cases, which causes downtime in our product.)

TL;DR DO NOT DO THIS! Data goes in the database, not functionality.
 

veri745

Golden Member
Oct 11, 2007
1,163
4
81
You could always add a generic polynomial formula, and allow users to specify the coefficients they would like to use in the formula to calculate a value.

The same could be done for an exponential equation.

This would provide a wide range of functionality without introducing the maintenance or security risks outlined above.
 

slugg

Diamond Member
Feb 17, 2002
4,723
80
91
Instead of accepting and storing a JavaScript function, accept and store an algaibraic expression. I'm sure you could find an expression library somewhere, but rolling your own expression tree parser is pretty simple. Split the string recursively in reverse order of operations and push into a stack; pop off the stack, evaluate, recurse until it's done. If the users are limited to specific arithmetic operators, it makes this even easier.

Safe, extensible from the user's perspective, and pretty simple. Validation is they key.

If you're die-hard set on storing and executing a function, you actually do have an option. Look at Node's "vm" module (built-in). I use it for sandboxing tests and providing a DSL in my functional test framework. Pretty powerful stuff, just make sure you pay attention to the details.