Skip to content
Browse files

dynamic role definitions

  • Loading branch information...
1 parent 5664312 commit cca6ab6e5786ff785c86e9fce4667ba5d9727ae8 @carlos8f committed Mar 5, 2013
Showing with 113 additions and 10 deletions.
  1. +25 −2 context.js
  2. +9 −1 index.js
  3. +4 −4 stores/memory.js
  4. +3 −3 stores/redis.js
  5. +72 −0 test/common.js
View
27 context.js
@@ -15,6 +15,11 @@ function copy (obj) {
function Context (name, structure) {
this.name = name;
this.roles = copy(structure);
+ this.update();
+}
+module.exports = Context;
+
+Context.prototype.update = function () {
var ctx = this;
this.verbs = Object.keys(ctx.roles).reduce(function (verbs, role) {
ctx.roles[role].forEach(function (verb) {
@@ -25,5 +30,23 @@ function Context (name, structure) {
});
return verbs;
}, {});
-}
-module.exports = Context;
+};
+
+Context.prototype.updateRole = function (name, verbs) {
+ this.roles[name] = copy(verbs);
+ this.update();
+};
+
+Context.prototype.addRole = function (name, verbs) {
+ if (typeof this.roles[name] !== 'undefined') {
+ var err = new Error('role already defined: ' + name);
+ err.code = 'ER_DUP_ROLE';
+ throw err;
+ }
+ this.updateRole(name, verbs);
+};
+
+Context.prototype.removeRole = function (name) {
+ delete this.roles[name];
+ this.update();
+};
View
10 index.js
@@ -8,7 +8,7 @@ relations.define = function (name, structure) {
relations[name] = function () {
var args = [].slice.call(arguments);
var str = args.shift();
- var str, named, unnamed, fn;
+ var str, named, unnamed, fn, raised = false;
do {
var arg = args.shift();
if (Array.isArray(arg)) {
@@ -31,6 +31,8 @@ relations.define = function (name, structure) {
} while (args.length);
function raiseErr (err) {
+ if (raised) return;
+ raised = true;
if (typeof err === 'string') err = new Error(err);
if (fn) return fn(err);
throw err;
@@ -87,9 +89,15 @@ relations.define = function (name, structure) {
}
});
+ if (raised) return;
+
cmd.ctx = ctx;
queue(cmd);
};
+
+ ['addRole', 'updateRole', 'removeRole'].forEach(function (method) {
+ relations[name][method] = ctx[method].bind(ctx);
+ });
};
relations.stores = {
View
8 stores/memory.js
@@ -39,11 +39,11 @@ store.on('revocation', function (cmd, cb) {
store.on('verb-question', function (cmd, cb) {
var subject = initSubject(cmd);
var can = Object.keys(subject.roles).some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
});
if (!can && cmd.object && subject.objects[cmd.object]) {
can = Object.keys(subject.objects[cmd.object]).some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
});
}
cb(null, can);
@@ -64,7 +64,7 @@ store.on('verb-request', function (cmd, cb) {
var subject = initSubject(cmd);
cb(null, Object.keys(subject.objects).filter(function (k) {
return Object.keys(subject.objects[k]).some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
});
}));
});
@@ -82,7 +82,7 @@ store.on('verb-subject-request', function (cmd, cb) {
subject = contexts[cmd.ctx.name][subject];
if (!subject.objects[cmd.object]) return false;
return Object.keys(subject.objects[cmd.object]).some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
});
}));
});
View
6 stores/redis.js
@@ -36,7 +36,7 @@ store.on('verb-question', function (cmd, cb) {
if (err) return cb(err);
if (!roles) roles = [];
var can = roles.some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
});
if (can || !cmd.object) return cb(null, can);
else {
@@ -75,7 +75,7 @@ store.on('verb-request', function (cmd, cb) {
var object = key.split(':').pop();
if (err || !roles || object == all) return cb_(err);
cb_(null, roles.some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
}) ? object : null);
});
}, function (err, objects) {
@@ -123,7 +123,7 @@ store.on('verb-subject-request', function (cmd, cb) {
var subject = key.split(':').slice(2, 3)[0];
if (err ) return cb_(err);
cb_(null, roles.some(function (role) {
- return ~cmd.ctx.verbs[cmd.verb].indexOf(role);
+ return cmd.ctx.verbs[cmd.verb] && ~cmd.ctx.verbs[cmd.verb].indexOf(role);
}) ? subject : null);
});
}, function (err, subjects) {
View
72 test/common.js
@@ -136,4 +136,76 @@ doBasicTest = function (store, options) {
done();
});
});
+
+ it('add owner role throws', function (done) {
+ assert.throws(function () {
+ relations.repos.addRole('owner', ['pull', 'push', 'administrate']);
+ }, function (err) {
+ return err.code === 'ER_DUP_ROLE';
+ });
+ done();
+ });
+
+ it('redefine owner', function (done) {
+ relations.repos.updateRole('owner', ['pull', 'push', 'administrate', 'absquatulate']);
+ done();
+ });
+
+ it('can carlos absquatulate buffet?', function (done) {
+ relations.repos('can %s absquatulate %s?', carlos, buffet, function (err, can) {
+ assert.ifError(err);
+ assert(can);
+ done();
+ });
+ });
+
+ it('what can carlos absquatulate?', function (done) {
+ relations.repos('what can %s absquatulate?', carlos, function (err, list) {
+ assert.ifError(err);
+ assert.deepEqual(list [buffet]);
+ done();
+ });
+ });
+
+ it('can brian absquatulate buffet?', function (done) {
+ relations.repos('can %s absquatulate %s?', brian, buffet, function (err, can) {
+ assert.ifError(err);
+ assert(!can);
+ done();
+ });
+ });
+
+ it('add scientist', function (done) {
+ relations.repos.addRole('scientist', ['test']);
+ relations.repos('%s is a scientist', sagar, done);
+ });
+
+ it('can sagar test views?', function (done) {
+ relations.repos('can %s test %s?', sagar, views, function (err, can) {
+ assert.ifError(err);
+ assert(can);
+ done();
+ });
+ });
+
+ it('can brian test views?', function (done) {
+ relations.repos('can %s test %s?', brian, views, function (err, can) {
+ assert.ifError(err);
+ assert(!can);
+ done();
+ });
+ });
+
+ it('remove scientist', function (done) {
+ relations.repos.removeRole('scientist');
+ done();
+ });
+
+ it('can sagar test views?', function (done) {
+ relations.repos('can %s test %s?', sagar, views, function (err, can) {
+ assert(err);
+ assert.equal(err.message, 'verb not defined: "test"');
+ done();
+ });
+ });
}

0 comments on commit cca6ab6

Please sign in to comment.
Something went wrong with that request. Please try again.