rethinkdb / horizon

Horizon is a realtime, open-source backend for JavaScript apps.
MIT License
6.78k stars 351 forks source link

Add more complex filtering using Validators #866

Open nbclark opened 7 years ago

nbclark commented 7 years ago

Currently using validators for read operations only serve to either validate all documents in the result set or trigger an error. Given the limited server-side filtering support, we've been a bit stuck with how to implement group ownership of documents, and restrict read access those documents only to the owners. The validator is close, but we want the server to be able to filter out documents from a result if the validator fails.

A proposed solution is a server option to enable validator filtering (as opposed to pure query blocking).

riyadhzen commented 7 years ago

Hi. Thank you so much for taking the time to look at the horizon project.

Can you please provide a use case or an example where your addition might help instead of blocking at query time (a simple example will suffice).

One more thing, do you believe that going forward with an option that might have performance implications is a good idea (please try to clarify in your answer).

Thanks in advance.

nbclark commented 7 years ago

Hey Riyadh,

Love the work you've done with horizon. We are looking to implement a variant of a chat application, where we want a conversation between 2 or more people, but want to restrict access to only those involved in the conversation. Typically we would model this as { userIDs: [1,2,3], createdBy: 1 }, or something to that effect.

With horizon, the whitelisting permissions are a bit simple, and restricting to a single owner is trivial (collection.findAll({user_id: userId()})). However, multiple owners does not appear to be supported.

The validator functionality on reads is approximately what we want (the ability to apply server-side logic to restrict queries). However, the restriction is a full block instead of a filter, so we have no way to construct a collection with Horizon with multiple owners, and restrict access from the server.

As far as performance implications, the pull request I submitted will not have any. The validator technique used to block iterates over the entire result set, and throws if an unauthorized document is encountered. My change does the same, except it replaces the throw with a filter.

Please let me know if you have further questions, and again thank you for all of your great work.

riyadhzen commented 7 years ago

Hi. I wonder if the following helps

lets say you have the following schema for users:

userSchema = {
  name: 'string',
  chatRooms: ['string'] // user allowed to chat only in these rooms
}

Now you can use the following validator function to allow users only to chat in rooms that they belong to (I assume that value contains name of chat room that it belongs to):

validator = """
  (context, value) => {
    if (context) { // context represents user in this case
      if (context.chatRooms && context.chatRooms.indexOf(value.chatRoom) !== -1){
         return true
      }
      return false
    }
    return false
  }
"""

I believe that this overcomes the following which you mentioned in your reply

However, the restriction is a full block instead of a filter, so we have no way to construct a collection with Horizon with multiple owners, and restrict access from the server.

this means that you can construct a chat room with multiple owners.

I hope that I didn't miss anything. cheers.