@parthar/rbac
Version:
Role Based Access Control
126 lines (103 loc) • 3.04 kB
JavaScript
;
// Permission => Resource & Actions
// store: [{res: "resource-name", acts: ["action-1", "action-2", ...]}]
const DELIMITER = "%";
const RES_REGEX = new RegExp(`^[^${DELIMITER}\\s]+$`);
const PERM_REGEX = new RegExp(`^([^${DELIMITER}]+)${DELIMITER}(.*)$`);
function makeString(res, act) {
return res + DELIMITER + act;
}
function addPerms2store(store, resource, actions) {
let perm;
perm = store.find(function find(ele) {
return ele.res === resource;
});
// sorted & unique actions
if (perm) {
perm.acts = Array.from(new Set(perm.acts.concat(actions).sort()));
} else {
store.push({
"res": resource,
"acts": Array.from(new Set(Array.from(actions).sort()))
});
}
}
function strings2store(store, arr) {
arr.forEach(function each(str) {
let matches = str.match(PERM_REGEX);
addPerms2store(store, matches[1], [matches[2]]); // eslint-disable-line no-magic-numbers
});
return store;
}
function store2strings(store) {
let strs = [];
store.forEach(function eachPerm(perms) {
perms.acts.forEach(function eachAct(act) {
strs.push(makeString(perms.res, act));
});
});
return strs.sort();
}
class Permissions {
static makeString(res, act) {
return makeString(res, act);
}
constructor(permStrs) {
this._store = [];
if (permStrs) {
strings2store(this._store, permStrs);
}
}
listResources() {
return this._store.map(e => e.res).sort();
}
actions4resource(res) {
let perm = this._store.find(function find(ele) {
return ele.res === res;
});
return perm ? perm.acts : null;
}
export() {
return store2strings(this._store);
}
can(res, act) {
let actions;
if (this.listResources().indexOf("*") >= 0) { // eslint-disable-line no-magic-numbers
return true;
}
actions = this.actions4resource(res);
if (actions) {
return actions.indexOf("*") >= 0 || actions.indexOf(act) >= 0; // eslint-disable-line no-magic-numbers
}
return false;
}
// fluent API
resource(res) {
if (!RES_REGEX.test(res)) {
throw new Error("badly-formatted resource token");
}
this._resource = res;
return this;
}
actions(arr) {
if (!this._resource) {
throw new Error("set resource before setting actions");
}
addPerms2store(this._store, this._resource, arr);
delete this._resource;
return this;
}
include(obj) {
strings2store(this._store, obj.export());
return this;
}
exclude(obj) {
let base = this.export();
let excl = obj.export();
let diff = base.filter(x => !excl.includes(x));
this._store = [];
strings2store(this._store, diff);
return this;
}
}
module.exports = Permissions;