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

miracle

v0.0.3

Published

Flexible role-based authorization solution that is a pleasure to use

Downloads

21

Readme

Miracle

Miracle is an ACL for NodeJS that was designed to be well-structuted, simple yet exhaustive. It uses permissions defined on resources, and roles are granted with the access to them.

To be a universal tool, it does not include any special cases, does not force you to persist and does not insist on any formats or conventions.

Maximum flexibility and total control. Enjoy! :)

Inspired by https://github.com/optimalbits/node_acl and https://npmjs.org/package/nod.

Reference

{:toc}

Define The Structure

Acl

To start using miracle, instantiate the Acl object:

var Acl = require('miracle').Acl;

var acl = new Acl();

The Acl object keeps track of your resources and permissions defined on them, handles grants over roles and provides utilities to manage them. When configured, you can check the access against the defined state.

Create

Methods from this section allow you to build the structure: list of roles, resources and permissions.

It's not required that you have the structure defined before you start granting the access: the grant() method implicitly creates all resources and permissions that were not previously defined.

Start with defining the resources and permissions on them, then you can grant a role with the access to some permissions on a resource.

addRole(roles)

Define role[s].

  • roles: the role[s] to define.

The role will have no permissions granted, but will appear in listRoles().

acl.addRole('admin');
acl.addRole(['anonymous', 'registered']);

acl.listRoles(); // -> ['admin', 'anonymous', 'registered']

addResource(resources)

Define resource[s].

  • resources: resource[s] to define.

The resource will have no permissions defined but will list in listResources().

acl.addResource('blog');
acl.addResource(['page', 'article']);

acl.listResources(); // -> ['blog', 'page', 'article']

addPermission(resources, permissions)

Define permission[s] on resource[s].

  • resources: resource[s] to define the permission on. Are created if were not previously defined.
  • permissions: permission[s] to define.

The defined permissions are not granted to anyone, but will appear in listPermissions().

acl.addPermission('blog', 'post');
acl.addPermission(['page', 'article'], ['create', 'read', 'update', 'delete']);

acl.listPermissions('page'); // -> ['create', 'read', 'update', 'delete']

add(structure)

Define the whole resource/permission structure with a single object.

  • structure: an object that maps resources to an array of permissions.
acl.add({
    blog: ['post'],
    page: ['create', 'read', 'update', 'delete'],
    article: ['create', 'read', 'update', 'delete'],
});

Remove

removeRole(roles)

Remove role[s] and their grants.

  • roles: role[s] to remove.
acl.removeRole('admin');
acl.removeRole(['anonymous', 'registered']);

removeResource(resources)

Remove resource[s] along with their grants and permissions.

  • resources: resource[s] to remove.
acl.removeResource('blog');
acl.removeResource(['page', 'article']);

removePermission(resources, permissions)

Remove permission[s] from resource[s].

  • resources: resource[s] to remove the permissions from.
  • permissions: permission[s] to remove.

The resource is not implicitly removed: it remains with an empty set of permissions.

acl.removePermissions('blog', 'post');
acl.removePermissions(['page', 'article'], ['create', 'update']);

List

listRoles()

Get the list of defined roles.

acl.listRoles(); // -> ['admin', 'anonymous', 'registered']

listResources()

Get the list of defined resources, including those with empty permissions list.

acl.listResources(); // -> ['blog', 'page', 'article']

listPermissions(resources)

Get the list of permissions for a resource, or for multiple resources.

  • resources: resource[s] to get the permissions for. Optional.
acl.listPermissions('page'); // -> ['create', 'read', 'update', 'delete']
acl.listPermissions(['blog', 'page']); // -> ['post', 'create', ... ]
acl.listPermissions(); // -> [ ..all.. ]

list([resources])

Get the structure: list of resources mapped to their permissions.

  • resources: resource[s] to get the structure for. Optional.

Returns an object: { resource: [perm, ...] }.

acl.list(); // -> { blog: ['post'], page: ['create', ...] }
acl.list('blog'); // -> { blog: ['post'] }
acl.list(['blog', 'page']); // -> { blog: ['post'], page: ['create', ...] }

Export and Import

There's no single 'export everything' method: instead, you sequentially export the list of roles, the structure (resources and permissions), and the grants:

var miracle = require('miracle');

var acl = new miracle.Acl();

// Export
var save = {
    roles: acl.listRoles(),
    struct: acl.list(),
    grants: acl.show()
};

// Import
acl.addRole(save.roles);
acl.add(save.struct);
acl.grant(save.grants);

Note: As the grant() method creates resources and roles implicitly, it's usually enough to export the grants. You'll only lose roles & resources with empty grants.

Grant Permissions

grant(roles, resources, permissions)

Grant permission[s] over resource[s] to the specified role[s].

Has multiple footprints:

  • grant(roles, resources, permissions) - grant the listed roles with permissions to the listed resources ;
  • grant(roles, grants) - grant permissions using a grant object that maps a list of permissions to a resource: { resource: [perm, ...] }.

Roles, resources and permissions are implicitly created if missing.

acl.grant(['admin', 'manager'], 'blog', ['create', 'update']);
acl.grant('anonymous', { page: ['view'] });

revoke(roles[, resources[, permissions]])

Revoke permission[s] over resource[s] from the specified role[s].

Has multiple footprints:

  • revoke(roles) remove grants from all resources ;
  • revoke(roles, resources) remove all grants from the listed resources ;
  • revoke(roles, resources, permissions) remove specific grants from the listed resources ;
  • revoke(roles, grants) - revoke grants using a grant object that maps a list of permissions to a resource: { resource: [perm, ...], ... }.

No roles, resources or permissions are removed implicitly.

acl.revoke('anonymous');
acl.revoke(['admin', 'manager'], 'blog', ['create', 'update']);
acl.revoke('anonymous', { page: ['view'] });

Authorize

check(roles[, resources[, permissions]])

Check whether the named role[s] have access to resource[s] with permission[s].

Has multiple footprints:

  • check(roles, resources): check whether the role[s] have any access to the named resource[s].
  • check(roles, resources, permissions): check with a specific set of permissions.
  • check(roles, grants): check using a grants object.

In order to pass the test, all roles must have access to all resources.

Returns a boolean.

acl.check('admin', 'blog'); // -> true
acl.check(['anonymous'], 'blog', 'read'); // -> true
acl.check('registered', { page: ['update', 'delete'] });

checkAny(roles[, resources[, permissions]])

Same as check, but the united permissions are checked.

In order to pass the test, any role having access to any resource is sufficient.

Also supports the checkAny(roles, grants) footprint.

Show Grants

which(roles)

Collect grants that each of the provided roles have (intersection).

acl.which('admin'); // -> { blog: ['post'] }

whichAny(roles)

Collect grants that any of the provided roles have (union).

acl.which(['anonymous', 'registered']); // -> { page: ['view'] }

show([roles])

Get all grants for the specified roles.

  • roles: role[s] to get the grants for.

Returns an object { role: { resource: [perm, ...] } }. Roles that were not defined are not mentioned in the result.

acl.show(); // -> { admin: { blog: ['post'] } }
acl.show('admin');
acl.show(['admin', 'anonymous']);