Best way to implement ACL with Mongoose - node.js

I have my data model already defined and implemented. I can very easily write manually the filter to filter out non-authorized results for the user who sent the query (which would be in the style of: "collection.acl.personId": queryPersonId )
My problem is, where and how should I write this "thing" to be as automatic as possible?
I tried to do it with a custom query and a static method, but did not had any luck on both.
Static method con: I don't want to rewrite all my code to use .then(). I want to keep the current chaining.
Custom query: it simply did not worked, even by following the doc.
Ideal the result would be something like
Model.findWithAcl(filters).lean()
Model.findOneWithAcl(filters).lean()
Note that we are using Typescript. The priority would be to have something working, but having the ability to have a working type would be the second priority right after.
Thanks for any help

Casl mongoose gives a very good way of filtering both results (row level) and fields from collections. Note that it also can be used in the front end.
Great package that works very well with auth0 rights.
https://casl.js.org/v5/en/guide/intro
https://casl.js.org/v5/en/package/casl-mongoose

Related

sails blueprints query in url not working

I have various GET http calls to my api with the following format:
/api/posts?userId=3
However, it is not filtering posts by its userId column, and just returns all posts, regardless of the posts' userId.
This syntax has worked in past projects I've had also, and is documented here. (The example they give is GET /purchase?amount=99.99).
Questions I've seen do not address the query language via defaults routes in this way, so I'm having trouble finding help. Any guesses on what could be going wrong?
UPDATE:
What does work as expected
req.query is getting set and read by policies (eg, ?userId=3 is found by req.param("userId"))
/api/posts?userId=3&populate=userId populates the userId field, (but still returns all posts for all users)
filtering by primary key (eg ?id=5) filters and returns only one record as expected
When working in the api, or in sails console, (eg Posts.find({userId: 3})) works
What does not work as expected
filtering by foreign keys (eg ?userId=6)
filtering by non-foreign keys (eg ?name=test)
filtering using where (eg &where={"userId":1})
It turns out I was adding a "where" clause to every query in a policy (eg, "where: {"status": "active"}}). Having a "where" in the query string automatically overrides the other params, and so nothing else was getting seen. (To be precise, if you have a where clause, other criteria never get seen)
For some reason, the "where" was also not working to set the search criteria for sails 0.12.13, so I ended up hacking the parseCriteria function actionUtils in sails and using the one they have for v.1 and that worked for me.
Hope that helps anyone in the future

How to do in MongoDB what would have been perfect for a stored procedure in SQL - recursive query

I have the following scenario in a CMS I am building in NodeJs with MongoDb. I have three collections, customData, queries, and templates. Queries can depend on customData, and templates can depend on customData, queries, and other templates. What I need to do is to be able to very quickly figure out all of the documents that depend on a particular item when that item changes. e.g. If a particular customData item changes, I need a list of all the queries and templates that depended on that customData, as well as recursively all the templates that depend on those queries and templates. I need to then take that list and flag all of those documents for processing/regeneration. This is accomplished by setting a regenerate property equal to true on each of the documents in the list. This is the sort of thing that would be perfect for a stored procedure in any database with stored procedures, but I'm struggling to figure out the best solution using MongoDb. Every other need of my project is perfectly suited for Mongo. This is the only scenario that I'm having trouble with.
One solution I've come up with is to store the dependencies on each document as an array of named items as follows (e.g. a doc in the templates collection):
{
name: "SomeTemplate",
...
dependencies: [{type: "query", name: "top5Products"}, {type: "template", name: "header"}]
}
The object above denotes a template that depends on the query named "top5Products" as well as the template named "header". If either of those documents change, this template needs to be flagged for regeneration. I can accomplish the above with a getAllDependentsOfItem function that calls the following on both the queries and templates collections, unioning the results, then recursively calling getAllDependentsOfItem on each result.
this.collection.find({dependencies: item })
For instance, if the query changes, I can call it as follows, then call something else to flag all of those results...
let dependents = this.dependencyService.getAllDependentsOfItem({type: "query", name: "top5Products"});
This just feels very messy to me, especially wrestling with Promises and the recursion above. I haven't even finished the above, but the whole idea of Promises and recursion just seems like a whole lot of cruft for something that would have been so simple in a stored procedure. I just need the dependent documents flagged, and having to wade through all my layers of NodeJs code (CustomDataService, QueryService, TemplateService, DependencyService) to accomplish the above just feels wrong. Not to mention the fact that I keep coming up with a circular dependency between DependencyService and the others. DependencyService needs to call the QueryService and TemplateService to actually talk to those collections, and they need to notify the DependencyService when something changes. I know there are ways around that like using events or not having a DependencyService at all, or just talking directly to the Mongo driver from the DependencyService, but I haven't found a solution that feels right yet.
Another idea I had was to record the dependencies in a completely new collection called "dependencies". Perhaps using a document schema like the following...
{
name: "SomeTemplate",
type: "template",
dependencies: [{type: "query", name: "top5Products"}, {type: "template", name: "header"}]
}
This way the dependencies can be tracked completely separately from the documents themselves. I haven't gotten very far on that solution though.
Any ideas will be greatly appreciated.
Update:
Anyone?
I've since written all the javascript in mongo shell that, given the type and name of a changed item, will recursively find all the dependents of that item and update those dependents, setting the regenerate flags on those documents to "1".
My problem now is - how do I run this code on the MongoDb server by calling it from NodeJs? I need NodeJs to control when this happens and pass the changed item into it. I've been looking at the eval command, and that just looks like a bad idea. I think it's been deprecated in MongoDb versions > 3.
I can't imagine how this recursive code I wrote using cursors in mongo shell could be anything but MUCH slower when run from inside NodeJs on a different server than the database. All the queries recursively getting each document, incurring the latency back and forth across servers, then looping through the results to update the regenerate flag on all the dependent documents... I just can't wrap my brain around why this can't and shouldn't be done on the server somehow. It seems like the perfect scenario for some sort of batch, server-side mechanism, like, I dunno, a stored procedure!
Please help me figure out either how to do this, or how to do it the "Mongo way". I can post the mongo shell code that is working if it would help.

How to make filters in queries optional

How to make a query filter bound to a request parameter inactive if the parameter is not present?
For example: I have a query MyQuery that can be accessed through the projection MyProjection. I add a filter to that query where I say that MyDate field should be equal to {Request.QueryString:MyDate}. I want URLs like ~/MyProjection?MyDate=2016-03-08 to filter content items by the given value, but the url ~/MyProjection to just not filter by that field. But this is not what happens: a condition gets added to the query anyway and it's of the form '[minimum DateTime value] < MyDate < [maximum DateTime value]'. This is not good because it will filter out fields with NULL values. If I try to do the same with a numeric field, it's even worse because it throws exceptions when the parameter is not present.
I know I can create a new query and projection to get different options, but that seems like an overkill - also, what if I wanted to create an advanced search form, it would have to target a single projection.
Is there an "official" way to do this? Or a workaround? Or is this simply not supported in Orchard?
I'm not aware of a way to do this out of the box. However, you could pretty easily create your own filter with the behavior you want by implementing IFilterProvider.
Take a look at the Orchard.Projections module. That's where you'll find many of the default query filters (including the date field filter you referenced). Your's will likely be even simpler if you only need to handle a specific case.
For a very simple example, checkout the Orchard.Tags module (look in the projections folder). The contents of this folder will give you pretty much all the boilerplate you'll need to get started creating your own. Just plug in your own logic.

Expression Engine - passing multiple categories as URL segments

I'm trying to create a product filter with deep-linking capability. Essentially, I want the user to be able to filter my product list on multiple categories and have the URL reflect the filtering they've done.
So it would start as:
www.site.com/products/
My first level of category filtering already works. So I can use EE's regular handling of URL segments to get to my first level of filtering. For instance:
www.site.com/products/leatherthongs
Returns a filtered subset showing only a spectacular collection of leather thongs. But now I want the user to be able to filter on another category - color for instance. This is where stuff stops working.
EE's way of handling multiple categories inside templates (with ampersands or pipes) doesn't work in the URL:
www.site.com/products/leatherthongs&red
Nor does any variation that I've tried.
My next move is to create a simple raw PHP method that can capture regular querystring parameters and then inject them into the {entries} tag before rendering. Not very difficult, but quite ugly. I would love to know if there is a way to handle multiple categories in the URL natively.
Thanks for your time.
Have you considered using Low's Seg2Cat add-on? I'm not sure how complex you want to make this but it seems that you could specify something in your channel:entries loop like categories='{segment_2){if segment_3}|{segment_3_category_id}{/if}'
This exact syntax is untested but I have had success in the past with a similar solution.

Misconeptions about search indexing? (Haystack/Whoosh)

I'm using haystack with whoosh for development purposes.
I want search results based on django models to be filtered by the user that created them.
Please see my other post Filter haystack result with SearchQuerySet for details.
Basically I had to add User to my search index. But I noticed, when I manually change the user_id of a record, search is broken. After thinking about it this even makes sense. But, this means I have to rebuild the index after each field update in each model? Surely that doesn't scale at all?
I thought the engine would find the object by id, then look it up in the database, and return a current instance for further processing like filtering. It seems like everything is cached in the index so must be synchronized in realtime for search results to show up? Am I missing something here?
This documentation helped shed some light:
http://docs.haystacksearch.org/dev/searchindex_api.html

Resources