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

@luislobo/rbac2

v1.1.3

Published

Simple RBAC checker with support for context checks.

Downloads

7

Readme

rbac2

NPM version Build Status

Simple RBAC checker with support for context checks.

Installation

npm install rbac2

Usage

Simple roles

var RBAC = require('rbac2');

var rules = [
    {a: 'author', can: 'publish posts'},
    {a: 'editor', can: 'edit posts'},
    {a: 'editor', can: 'author'},
    {a: 'admin',  can: 'editor'},
    {a: 'admin',  can: 'do admin'}
];

var rbac = new RBAC(rules);

// Perform a check
rbac.check('admin', 'edit posts', function (err, result) {
    // result: true
});

Adding context checks

You can specify context checks in rules by adding a when function:

var rules = [
    {a: 'author', can: 'publish posts'},
    {a: 'editor', can: 'edit posts'},
    {a: 'user',   can: 'editor', when: function (params, callback) {
        db.findOne('tbl_post_editors', {
            'post_id': params.postId,
            'user_id': params.userId
        }, callback);
    }},
    {a: 'editor', can: 'author'},
    {a: 'admin',  can: 'editor'},
    {a: 'admin',  can: 'do admin'}
];

And check by passing context parameters:

rbac.check('user', 'edit posts', {postId: 23, userId:12}, function (err, result) {
    // ...
});

In the code above, we set the rule that any user can become the editor for a post only if that user has the 'editor' role for the post in the database. Here, when is a user-provided check that will be given params from the check call.

After doing business logic checks, the when function should call the callback as callback(err, result), where result should be boolean. (If err is not null, then result is considered false)

About rules

No subject, role or permission - only hierarchy

This is valid:

var rules = [
    {a: 'editor',     can: 'edit posts'},
    {a: 'edit posts', can: 'change post url'}
];

Cyclic hierarchy is NOT supported

This is invalid:

var rules = [
    {a: 'admin', can: 'user'},
    {a: 'user',  can: 'admin', when: function (err, callback) {...}}
];

and will result in an indefinite loop.

Conditional and non-conditional paths

Given these rules:

var rules = [
    {a: 'editor', can: 'edit posts'},
    {a: 'user',   can: 'editor', when: function (params, callback) {
        // business logic check
    }},
    {a: 'admin',  can: 'user'}
];

If we check from a 'user' role:

rbac.check('user', 'edit posts', {...}, function (err, res) {
    // ...
});

The following path is checked:

'user' --> 'editor' [conditional] --> 'edit posts'

To go from 'user' to 'editor', the context condition must be satisfied.

But, if we check from a 'admin' role:

rbac.check('admin', 'edit posts', function (err, res) {
    // ...
});

The following path is checked:

'admin' --> 'user' --> 'editor' [conditional] --> 'edit posts'

To go from 'admin' to 'user', there is no condition. So the rest of the path is considered to be checked AND successful.

If the whole path is needed to be checked, then you can instantiate RBAC with an optional second parameter, checkFullPath, or set it after creating the object. It defaults to false, unless set.

var RBAC = require('rbac2', true);

or

var RBAC = require('rbac2');
RBAC.checkFullPath = true;

In general: Paths are traveresed continuously till conditional checks exist; if a node in the path is hopped without a conditional check, the remaining path is considered to be solved and the result is true. If checkFullPath, then the whole path needs to be satisfied until the end.

Multiple paths to same permission

For the following rules:

var rules = [
    {a: 'editor', can: 'edit posts'},
    {a: 'user',   can: 'editor', when: function (params, callback) {
        // business logic check
    }},
    {a: 'user',   can: 'edit posts'}
];

If you do the following check:

rbac.check('user', 'edit posts', function (err, res) {
    // ...
});

Then we have these possible paths:

1] 'user' --> 'edit posts'
2] 'user' --> 'editor' [conditional] --> 'edit posts'

Paths are checked in serial order. The shortest path is picked up first (though it might not take the least time if conditional). When the match is found, any remaining paths are not checked and the result is returned immediately.

Caching of rule trees

If you have a large/complex set of rules with roles inheriting from other roles, generating the tree for the role can take a significant amount of time (tens of milliseconds). To speed up the checks, you can ask rbac to cache the tree for each role once it has been generated, at the expense of slightly more use of memory to hold the cached trees.

To use in-memory caching of the trees, instantiate RBAC with an optional third parameter, cacheTrees, or set it after creating the object. It defaults to false, unless set.

var RBAC = require('rbac2', false, true);

or

var RBAC = require('rbac2');
RBAC.cacheTrees = true;

Testing

Install dev dependencies and run:

npm test

Roadmap

  • Implement support for async/await/promises on check and when functions

License

MIT