npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mongoose-resource-management

v1.0.9

Published

Downloads

11

Readme

Mongoose Resource Management(ABAC like)

A simple resource management system for mongoose.
This is a work in progress.

Managing hierarcy of resources is a common problem in many applications. This module provides a simple way to manage resources in a mongoose database.

The idea is having a new collection to store resources. Each resource has a type,ref and path. The path is a string that represents the path of the resource in the hierarchy. You can see its almost like a file system.

The modulede injects middlewares(hooks) to keep resource collection updated.

While an Attribute-based access control(ABAC) systems offer rich mechanisims to implement authorization this module does not cover all requirements of an ABAC. Its simple yet usefull and quite trivial to get starting.

Defining a resource

var mongoose = require('mongoose');
var mrm = require('mongoose-resource-management');

var buidlingSchema = new mongoose.Schema({
    address: String,
    name: String,
});

//it is important to register the resource before mongoose compiling the model 
//if you dont, the resource will not be created in the database
mrm.registerResource({
    buidlingSchema,
    resourceType: "building",
    parent: null, //indicates that this is a root resource
});

//now you can compile the model
var Building = mongoose.model('Building', buidlingSchema);


var roomSchema = new mongoose.Schema({
    name: String,
    building: { type: mongoose.Schema.Types.ObjectId, ref: 'Building' },
});

mrm.registerResource({
    roomSchema,
    resourceType: "room",
    parent: {
        localField: "building", //the field in the roomSchema that references the parent resource
        resourceType: "building", //the type of the parent resource
    }
});

var Room = mongoose.model('Room', roomSchema);

Configuring the module

var mongoose = require('mongoose');
var mrm = require('mongoose-resource-management');

//you can define whcih collection you would like to  use as resource collection
//its a good practice to create indexes for the fields ref and path
mrm.configure(mongoose,{
   refField: "ref",
   pathField: "path",
   resourceTypeField: "type",
   collection:"my_resources"
});

Creating a resource

var building = new Building({
    address: "123 Main St",
    name: "Main Building",
});

await building.save();
//this will create a resource in the resource collection as follows
/*
{
    _id: ObjectId("5f0b1b3b9b0b9b0b9b0b9b0b"),
    ref: ObjectId("5f0b1b3b9b0b9b0b9b0b9b0b"),
    path: "/building/5f0b1b3b9b0b9b0b9b0b9b0b",
    type: "building",
}
*/

var room = new Room({
    name: "Room 1",
    building: building._id,
});

await room.save();

//this will create a resource in the resource collection as follows

/*
{
    _id: ObjectId("5f0b1b3b9b0b9b0b9b0b9b0c"),
    ref: ObjectId("5f0b1b3b9b0b9b0b9b0b9b0c"),
    path: "/building/5f0b1b3b9b0b9b0b9b0b9b0b/room/5f0b1b3b9b0b9b0b9b0b9b0c",
    type: "room",
}

Access Control

You can use the resource collection to manage access control to your resources. Storing resourceKeys in users session and checking them against the resource collection is a simple way to manage access control.

It is a good practice to check resource access then continue with your logic. This way you can prevent users from accessing resources they dont have access to. For example you have an endpoint as POST /room/5f0b1b3b9b0b9b0b9b0b9b0c/checkout and you want to check if the user has access to this room before you continue with the checkout logic.


const resourceKeys = [
    "/", // <--- This will give access to all resources
    "/building/5f0b1b3b9b0b9b0b9b0b9b0b", // <--- This will give access to all resources under this building
    "/building/5f0b1b3b9b0b9b0b9b0b9b0b/room/5f0b1b3b9b0b9b0b9b0b9b0c", // <--- This will give access to this room only
    "/building/5f0b1b3b9b0b9b0b9b0b9b0b/room" // <--- This will give access to all rooms under this building
]

const ref= ObjectId("5f0b1b3b9b0b9b0b9b0b9b0c"); //assume we are trying to access this room
const resource = mrm.getResource(ref,"room",resourceKeys); //this will return the resource if the user has access to it, otherwise it will return null

if(!resource){
    //user does not have access to this resource
    return;
}

//user has access to this resource you can continue with your logic

Search

Search is one of the most complex operations when it comes to access control in a resource hierarchy. Think about it, you wont return 403 for unauthorized search you just simply return empty array [].

This module provides a simple way to search resources in a hierarchy with helper functions.

Assume we are searching for rooms with name like "ro" in it. We want to search only in the resources that the user has access to.

const resourceKeys = [
    "/building/5f0b1b3b9b0b9b0b9b0b9b0b/room" // <--- This will give access to all rooms under 5f0b1b3b9b0b9b0b9b0b9b0b building
]

Rooms.aggregate([{
    $match:{
        name: /ro/i
    },
}
    ...mrm.getResourceFilters("room",resourceKeys), //<-- this will return the filters that will limit the search to the resources that the user has access to and add resource field to the document
    //it doesnt consider if resource is found or not, it just adds the filters to the pipeline and unwind with preserveNullAndEmptyArrays:true
    //this way you can still get the documents that are not in the resource collection
    //but that means the user has access to all resources, consider updating the resource collection
    {
        $skip:10, //<--
    },
    {
        $limit:10,
    }

])

Deleting a resource

await room.remove();
//this will delete the resource from the resource collection

Recreating your resources

This methods is useful when you want to recreate your resources. For example you have a resource collection that is not up to date and you want to recreate it.



await mrm.recreateResources({
    model:Building,
    resourceType:"building",
    parent:null,//<-- this is a root resource
}); 

//or you can recreate lover level resources
await mrm.recreateResources({
    model:Room,
    resourceType:"room",
    parent:{
        localField:"building",
        resourceType:"building",
    },
}); 

TODO

  • [ ] CI for unit testing(should work inmemory mongodb)
  • [ ] clearance like permit, allow, etc
  • [ ] typescript
  • [ ] Build Resource Tree feature