permits

0.1.2 • Public • Published

Permits (Permissions)

Simple but powerful in memory permission manager and query interface. Allows you to set permissions for users on resources with arbitrary string ids. Also has change event callbacks for syncronizing with persistent store.

Install

npm install permits

Philosophy

This library assumes that all things are identified by unique string ids. There are 3 fundamental building blocks, the user, the resource and the action to be taken. This allows you to set and get which user can take what action on which resource. All data is stored in a nested object to reduce the total number of keys on a single object since there could be very very many. The entire nested structure can be easily filtered over to find any particular combination of entries.

Usage

  var Permits = require('permits')
 
  var permissions = Permits()
 
  //gives "userid" the ability to do "allowedAction" on "resourceid"
  var result = permissions.allow('userid','resourceid','allowedAction')
 
  // result is a permissions object in the form 
  // { 
  //   userid:'userid',
  //   resourceid:'resourceid',
  //   action:'action'
  //   allowed:true,
  //   type:'default' //optionally define a resource type, defaults to "default"
  //  }
 
  //can == true
  var can = permissions.can('userid','resourceid','allowedAction')
 
  //denys user ability to do deniedAction
  var result = permissions.deny('userid','resourceid','deniedAction')
 
  //can == false
  var can = permissions.can('userid','resourceid','deniedAction')
 
  //clear user ability to do neutralAction
  var result = permissions.clear('userid','resourceid','neutralAction')
 
  //can == null
  var can = permissions.can('userid','resourceid','neutralAction')

Restore and Persist

Restore permissions from a persistent data store and syncronizes any changes back into the database.

  //assume we have a persistent store
  var Store = require('permissionStore')
  var Permits = require('permits')
  
  function upsert(permission,path){
    //assume store has an upsert function which takes an object with an id property
    permissions.id = path.join('.')
    Store.upsert(permissions)
  }
 
  //assume store gets entire table as an array with getAll()
  var permissions = Permits(Store.getAll(),upsert)
 
 //any new permissions will be upserted into database
 permissions.allow(...)
 

Resource Types

You may want to organize your resources by types and scope your permission methods to those types.

  var Permits = require('permits')
 
  //your global permissions, this object works on the default permission type: 'default'
  var permissions = Permits(resume,onChange)
 
  //create permission types called books, which will still be accessible from the permissions object.
  var books = permissions.type('books')
 
  //these changes will trigger onChange callback on the permissions object
  books.allow('someuser','booktitle','canRead')
 
  //true
  books.can('someuser','booktitle','canRead')
 
  //access book types from the main permissions object. always will be consistent with
  //other resource types, since they share the same object.
  permissions.type('books').get('someuser','booktitle','canRead')
  //this does the exact same thing
  permissions.get('someuser','booktitle','canRead','books')
 
  //returns a permissions object
  //{
  //  userid:'someuser',resourceid:'booktitle',action:'canRead',allowed:true, type:'books'
  //}
 
  //or use the default permission type
  permissions.deny(/*etc...*/)
  

Permissions Object

This is how the permissions object is returned and emitted through change callbacks.

 { 
   userid:'userid',
   resourceid:'resourceid',
   action:'action'
   allowed:true,  //allowed can be true false or null
   type:'default' //optionally define a resource type, defaults to "default"
  }

Internally The permissions object resides in a nested object organized into this structure:

  {
    userid:{
      type:{
        resourceid:{
          action:true //true false or undefined
        }
      }
    }
  }

It is accessed through lodash .get and .set methods. It will also be returned as a path on change:

  path = [userid,type,resourceid,action]

You can use this to create a unique id for insertion into a traditional database.

API

Initialize

Permits takes 3 options, an array of permissions, a callback function which gets executed every time permissions change and a string to define the default permissions type.

Permits(resume,upsert,defaultType)

  • resume(optional, array) - An array of permission objects to restore previous state.
  • upsert(optional, function) - A callback function which can take 2 parameters function upsert(permission,path){}
    • permission - A permissions object which was just updated, in the form

       { 
         userid:'userid',
         resourceid:'resourceid',
         action:'action'
         allowed:true,  //allowed can be true false or null
         type:'default' //optionally define a resource type, defaults to "default"
        }
    • path - the unique path to this permission object as an array. Use to create your own ID in the form: [userid,type,resourceid,action]

  • defaultType(optional, string) - defaults to the string 'default'. Set to whatever your default permissions resource type should be.

Type

Creating a resource type is optional, by default just initialize the permits class and it is ready to be used. If you need the ability to define seperate resources then use this function. All functions on the returned object will be scoped to whatever resource type you define. It has the same API as the permits object.

  var books = permits.type('books')
  //use books like a permits object, it has all the same functions

Set

Multiple ways to set new permissions, they all trigger on change callback. Type is optional and defaults to the either the default type, or the custom type.

permits.set(userid,resourceid,action,allowed,type)
permits.allow(userid,resourceid,action,type)
permits.deny(userid,resourceid,action,type)
permits.clear(userid,resourceid,action,type)

Get

Gets full permissions object. Type is optional to override the default type.

permits.get(userid,resourceid,action,type)

Can

Get a true, false or null answer for if a user can do something on a resource. Type is optional to override default type.

var result = permits.can(userid,resourceid,action,type)

Queries

There are many helper queries to get lists of permissions. These iterate over the entire structure, scoped to the resource type. Type is optional to override the default type.

permits.getByUser(userid,type)
permits.getByResource(resourceid,type)
permits.getByUserAndResource(userid,resourceid,type)
permits.getByUserAndAction(userid,action,type)
permits.getByResourceAndAction(resourceid,action,type)

  • returns - An array of permission objects, or an empty array if none are found.

Filter

If you need more search options you can filter directly on any permission parameter. All parameters optional, if none provided all permissions will be returned, which is the same as permit.list(). One caveat is that if you are filtering from a typed permissions, then it will only filter over that type. Use the root permits object to search over all types.

  var result = permits.filter({
    userid:'userid',         //optional userid to match, searches all users if omitted.
    resourceid:'resourceid', //optional resource id to match, searches all resources if omitted.
    action:'action',         //optional action to match, searches all actions if omitted.
    allowed:true,            //optional allowed to match, can be true or false. Searches all allowed states if omitted.
    type:'type',             //optional type to match. Searches all default type if omitted.
  })

List

Get the entire permissions store as a list of permission objects. If using a typed permission, then it will only return the entirety of that type. Use the root permits object to get entire list. Type is optional.

var list = permits.list(type)

Package Sidebar

Install

npm i permits

Weekly Downloads

1

Version

0.1.2

License

ISC

Unpacked Size

18.2 kB

Total Files

5

Last publish

Collaborators

  • daywiss