connect-roles
Advanced tools
Comparing version 2.1.0 to 3.0.0
@@ -0,1 +1,7 @@ | ||
3.0.0 / 2014-02-19 | ||
================== | ||
* Complete redesign so it's not a singleton anymore | ||
* Don't set the user when anonymous (this confused way too many people) | ||
2.1.0 / 2013-06-13 | ||
@@ -2,0 +8,0 @@ ================== |
204
index.js
"use strict"; | ||
var debug = require('debug')('connect-roles'); | ||
var Promise = require('promise'); | ||
var ert = require('ert'); | ||
var pathToRegexp = require('path-to-regexp'); | ||
var functionList = []; | ||
var failureHandler = function failureHandler(req, res, action) { | ||
res.send(403); | ||
}; | ||
var defaultUser = {}; | ||
module.exports = ConnectRoles; | ||
function ConnectRoles(options) { | ||
options = options || {}; | ||
this.functionList = []; | ||
this.failureHandler = options.failureHandler || defaultFailureHandler; | ||
this.async = options.async || false; | ||
this.userProperty = options.userProperty || 'user'; | ||
} | ||
var exports = module.exports = function middleware(req, res, next) { | ||
if (res.locals) attachHelpers(req, res.locals); | ||
attachHelpers(req, req); | ||
next(); | ||
}; | ||
exports.use = use; | ||
function use() { | ||
ConnectRoles.prototype.use = function () { | ||
if (arguments.length === 1) { | ||
use1.apply(this, arguments); | ||
this.use1(arguments[0]); | ||
} else if (arguments.length === 2) { | ||
use2.apply(this, arguments); | ||
this.use2(arguments[0], arguments[1]); | ||
} else if (arguments.length === 3) { | ||
@@ -30,12 +26,13 @@ use3.apply(this, arguments); | ||
} | ||
} | ||
}; | ||
function use1(fn) { | ||
if (typeof fn !== 'function') throw new Error('Expected fn to be of type function'); | ||
functionList.push(fn); | ||
} | ||
function use2(action, fn) { | ||
if (typeof action !== 'string') throw new Error('Expected action to be of type string'); | ||
if (action[0] === '/') throw new Error('action can\'t start with `/`'); | ||
use1(function (req, act) { | ||
ConnectRoles.prototype.use1 = function (fn) { | ||
if (typeof fn !== 'function') throw new TypeError('Expected fn to be of type function'); | ||
this.functionList.push(fn); | ||
}; | ||
ConnectRoles.prototype.use2 = function (action, fn) { | ||
if (typeof action !== 'string') throw new TypeError('Expected action to be of type string'); | ||
if (action[0] === '/') throw new TypeError('action can\'t start with `/`'); | ||
this.use1(function (req, act) { | ||
if (act === action) { | ||
@@ -45,4 +42,4 @@ return fn(req); | ||
}); | ||
} | ||
function use3(action, path, fn) { | ||
}; | ||
ConnectRoles.prototype.use3 = function (action, path, fn) { | ||
if (typeof path !== 'string') throw new Error('Expected path to be of type string'); | ||
@@ -57,3 +54,3 @@ var keys = []; | ||
keys.forEach(function (key, i) { | ||
req.params[key.name] = match[i+1]; | ||
req.params[key.name] = match[i + 1]; | ||
}); | ||
@@ -65,37 +62,72 @@ return fn(req); | ||
exports.can = routeTester('can'); | ||
exports.is = routeTester('is'); | ||
exports.isAuthenticated = isAuthenticated; | ||
function isAuthenticated(req,res,next) { | ||
if(arguments.length === 0){ return isAuthenticated; } | ||
if (req.user && req.user.isAuthenticated === true){ next(); } | ||
else if(req.user){ failureHandler(req, res, "isAuthenticated"); } | ||
else { throw new Error("Request.user was null or undefined, include middleware"); } | ||
ConnectRoles.prototype.can = routeTester('can'); | ||
ConnectRoles.prototype.is = routeTester('is'); | ||
ConnectRoles.prototype.isAuthenticated = function () { | ||
var msg = 'Expected req.isAuthenticated to be a function. ' | ||
+ 'If you are using passport, make sure the passport ' | ||
+ 'middleware comes first'; | ||
var res = function (req, res, next) { | ||
if (typeof req.isAuthenticated !== 'function') { | ||
throw new Error(msg); | ||
} | ||
if (req.isAuthenticated()) return next(); | ||
else return this.failureHandler(req, res, "isAuthenticated"); | ||
}.bind(this); | ||
res.here = function (req, res, next) { | ||
if (typeof req.isAuthenticated !== 'function') { | ||
throw new Error(msg); | ||
} | ||
if (req.isAuthenticated()) return next(); | ||
else return next('route'); | ||
}.bind(this); | ||
return res; | ||
}; | ||
exports.setFailureHandler = setFailureHandler; | ||
function setFailureHandler(fn) { | ||
failureHandler = fn; | ||
}; | ||
exports.setDefaultUser = setDefaultUser; | ||
function setDefaultUser(user) { | ||
defaultUser = user; | ||
}; | ||
function tester(req, verb){ | ||
return function(action){ | ||
var result = null; | ||
for (var i = 0; i<functionList.length && result === null; i++){ | ||
var fn = functionList[i]; | ||
ConnectRoles.prototype.test = function (req, action) { | ||
if (this.async) { | ||
return this.functionList.reduce(function (accumulator, fn) { | ||
return accumulator.then(function (result) { | ||
if (typeof result === 'boolean') return result; | ||
else return fn(req, action); | ||
}); | ||
}, Promise.from(null)).then(function (result) { | ||
if (typeof result == 'boolean') return result; | ||
else return false; | ||
}); | ||
} else { | ||
for (var i = 0; i < this.functionList.length; i++){ | ||
var fn = this.functionList[i]; | ||
var vote = fn(req, action); | ||
if (typeof vote === 'boolean') { | ||
result = vote | ||
return vote; | ||
} | ||
} | ||
debug('Check Permission: ' + (req.user.id||req.user.name||"user") + | ||
"." + (verb || 'can') + "('" + action + "') -> " + (result === true)); | ||
return (result === true); | ||
}; | ||
return false; | ||
} | ||
}; | ||
ConnectRoles.prototype.middleware = function (options) { | ||
options = options || {}; | ||
var userProperty = options.userProperty || this.userProperty; | ||
return function (req, res, next) { | ||
if (req[userProperty] && res.locals && !res.locals[userProperty]) | ||
res.locals[userProperty] = req[userProperty]; | ||
if (req[userProperty]) { | ||
req[userProperty].is = tester(this, req,'is'); | ||
req[userProperty].can = tester(this, req,'can'); | ||
} | ||
req.userIs = tester(this, req, 'is'); | ||
req.userCan = tester(this, req, 'can'); | ||
if (res.locals) { | ||
res.locals.userIs = tester(this, req, 'is'); | ||
res.locals.userCan = tester(this, req, 'can'); | ||
if (typeof req.isAuthenticated === 'function') | ||
res.locals.isAuthenticated = req.isAuthenticated.bind(req); | ||
} | ||
next(); | ||
}.bind(this); | ||
}; | ||
function tester(roles, req, verb) { | ||
return function (action) { | ||
var act = ert(req, action); | ||
return roles.test(req, act) | ||
} | ||
} | ||
@@ -105,25 +137,37 @@ | ||
return function (action){ | ||
return function (req, res, next) { | ||
if(tester(req,verb)(action)){ | ||
next(); | ||
}else{ | ||
//Failed authentication. | ||
failureHandler(req, res, action); | ||
} | ||
}; | ||
function handle(onFail) { | ||
return function (req, res, next) { | ||
var act = ert(req, action); | ||
if (this.async) { | ||
this.test(req, act).done(function (result) { | ||
if (result) { | ||
next(); | ||
} else { | ||
//Failed authentication. | ||
onFail(req, res, next, act); | ||
} | ||
}.bind(this), next); | ||
} else { | ||
if(this.test(req, act)){ | ||
next(); | ||
}else{ | ||
//Failed authentication. | ||
onFail(req, res, next, act); | ||
} | ||
} | ||
}.bind(this); | ||
} | ||
var failureHandler = this.failureHandler; | ||
var result = handle.call(this, function (req, res, next, act) { | ||
failureHandler(req, res, act); | ||
}); | ||
result.here = handle.call(this, function (req, res, next) { | ||
next('route'); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function attachHelpers(req, obj) { | ||
var oldUser = req.user; | ||
obj.user = req.user || Object.create(defaultUser); | ||
if(oldUser){ | ||
obj.user.isAuthenticated = true; | ||
}else{ | ||
obj.user.isAuthenticated = false; | ||
} | ||
if(obj.user){ | ||
obj.user.is = tester(req,'is'); | ||
obj.user.can = tester(req,'can'); | ||
} | ||
} | ||
function defaultFailureHandler(req, res, action) { | ||
res.send(403); | ||
} |
{ | ||
"name": "connect-roles", | ||
"description": "Provides dynamic roles based authentication for node.js connect and express servers.", | ||
"version": "2.1.0", | ||
"description": "Provides dynamic roles based authorization for node.js connect and express servers.", | ||
"version": "3.0.0", | ||
"homepage": "http://documentup.com/ForbesLindesay/connect-roles", | ||
@@ -12,3 +12,2 @@ "repository": { | ||
"devDependencies": { | ||
"should": "*", | ||
"mocha": "*" | ||
@@ -32,5 +31,6 @@ }, | ||
"dependencies": { | ||
"debug": "0.7.2", | ||
"path-to-regexp": "0.0.2" | ||
"path-to-regexp": "0.0.2", | ||
"ert": "1.0.1", | ||
"promise": "~4.0.0" | ||
} | ||
} |
156
readme.md
# Connect Roles | ||
<img src="http://i.imgur.com/opZKqAi.png" align="right"/> | ||
Connect roles is designed to work with connect or express. It is an authorisation provider, not an authentication provider. It is designed to support context sensitive roles/abilities, through the use of middleware style authorisation strategies. | ||
Connect roles is designed to work with connect or express. It is an authorisation provider, not an authentication provider. It is designed to support context sensitive roles/abilities, through the use of middleware style authorisation strategies. | ||
If you're looking for an authentication system I suggest you check out [passport.js](https://github.com/jaredhanson/passport) | ||
If you're looking for an authentication system I suggest you check out [passport.js](https://github.com/jaredhanson/passport), which works perfectly with this module. | ||
@@ -20,8 +20,22 @@ [![Build Status](https://secure.travis-ci.org/ForbesLindesay/connect-roles.png?branch=master)](http://travis-ci.org/ForbesLindesay/connect-roles) | ||
var authentication = require('your-authentication-module-here'); | ||
var user = require('connect-roles'); | ||
var ConnectRoles = require('connect-roles'); | ||
var express = require('express'); | ||
var app = express(); | ||
var user = new ConnectRoles({ | ||
failureHandler: function (req, res, action) { | ||
// optional function to customise code that runs when | ||
// user fails authorisation | ||
var accept = req.headers.accept || ''; | ||
res.status(403); | ||
if (~accept.indexOf('html')) { | ||
res.render('access-denied', {action: action}); | ||
} else { | ||
res.send('Access Denied - You don\'t have permission to: ' + action); | ||
} | ||
} | ||
}); | ||
app.use(authentication) | ||
app.use(user); | ||
app.use(user.middleware()); | ||
@@ -32,10 +46,10 @@ //anonymous users can only access the home page | ||
user.use(function (req, action) { | ||
if (!req.user.isAuthenticated) return action === 'access home page'; | ||
if (!req.isAuthenticated()) return action === 'access home page'; | ||
}) | ||
//moderator users can access private page, but | ||
//they might not be the only one so we don't return | ||
//they might not be the only ones so we don't return | ||
//false if the user isn't a moderator | ||
user.use('access private page', function (req) { | ||
if (req.user.role ==== 'moderator') { | ||
if (req.user.role === 'moderator') { | ||
return true; | ||
@@ -52,14 +66,3 @@ } | ||
//optionally controll the access denid page displayed | ||
user.setFailureHandler(function (req, res, action){ | ||
var accept = req.headers.accept || ''; | ||
res.status(403); | ||
if (~accept.indexOf('html')) { | ||
res.render('access-denied', {action: action}); | ||
} else { | ||
res.send('Access Denied - You don\'t have permission to: ' + action); | ||
} | ||
}); | ||
app.get('/', user.can('access home page'), function (req, res) { | ||
@@ -80,33 +83,40 @@ res.render('private'); | ||
To access all methods, you must construct an instance via: | ||
```js | ||
var ConnectRoles = require('connect-roles'); | ||
var roles = new ConnectRoles(options); | ||
``` | ||
### roles.use(fn(req, action)) | ||
Define and authorisation strategy which takes the current request and the action being performed. fn may return `true`, `false` or `undefined`/`null` | ||
Define and authorisation strategy which takes the current request and the action being performed. fn may return `true`, `false` or `undefined`/`null` | ||
If `true` is returned then no further strategies are considred, and the user is **granted** access. | ||
If `true` is returned then no further strategies are considred, and the user is **granted** access. | ||
If `false` is returned, no further strategies are considered, and the user is **denied** access. | ||
If `false` is returned, no further strategies are considered, and the user is **denied** access. | ||
If `null`/`undefined` is returned, the next strategy is considerd. If it is the last strategy then access is **denied**. | ||
If `null`/`undefined` is returned, the next strategy is considerd. If it is the last strategy then access is **denied**. | ||
### roles.use(action, fn(req)) | ||
The strategy `fn` is only used when the action is equal to `action`. It has the same behaviour with regards to return values as `roles.use(fn(req, action))` (see above). | ||
The strategy `fn` is only used when the action is equal to `action`. It has the same behaviour with regards to return values as `roles.use(fn(req, action))` (see above). | ||
It is equivallent to calling: | ||
It is equivallent to calling: | ||
```javascript | ||
roles.use(function (req, act) { | ||
if (act === action) { | ||
return fn(req); | ||
} | ||
}); | ||
``` | ||
```javascript | ||
roles.use(function (req, act) { | ||
if (act === action) { | ||
return fn(req); | ||
} | ||
}); | ||
``` | ||
**N.B.** The action must not start with a `/` character or it will call `roles.use(path, fn(req, action))` | ||
**N.B.** The action must not start with a `/` character | ||
### roles.use(action, path, fn(req)) | ||
Path must be an express style route. It will then attach any parameters to `req.params`. | ||
Path must be an express style route. It will then attach any parameters to `req.params`. | ||
e.g. | ||
e.g. | ||
@@ -119,9 +129,9 @@ ```javascript | ||
Note that this authorisation strategy will only be used on routes that match `path`. | ||
Note that this authorisation strategy will only be used on routes that match `path`. | ||
It is equivallent to calling: | ||
It is equivallent to calling: | ||
```javascript | ||
var keys = []; | ||
var exp = pathToRegexp(path); | ||
var exp = pathToRegexp(path, key); | ||
roles.use(function (req, act) { | ||
@@ -133,3 +143,3 @@ var match; | ||
keys.forEach(function (key, i) { | ||
req.params[key.name] = match[i+1]; | ||
req.params[key.name] = match[i + 1]; | ||
}); | ||
@@ -143,5 +153,5 @@ return fn(req); | ||
`can` and `is` are synonyms everywhere they appear. | ||
`can` and `is` are synonyms everywhere they appear. | ||
You can use these as express route middleware: | ||
You can use these as express route middleware: | ||
@@ -159,10 +169,21 @@ ```javascript | ||
### req.user.can(action) and req.user.is(action) | ||
If you want to skip only the current routes, you can also use `.here` | ||
`can` and `is` are synonyms everywhere they appear. | ||
```js | ||
app.get('/', user.can('see admin page').here, function (req, res, next) { | ||
res.render('admin-home-page'); | ||
}); | ||
app.get('/', function (req, res, next) { | ||
res.render('default-home-page'); | ||
}); | ||
``` | ||
These functions return `true` or `false` depending on whether the user has access. | ||
### req.userCan(action) and req.userIs(action) | ||
e.g. | ||
`can` and `is` are synonyms everywhere they appear. | ||
These functions return `true` or `false` depending on whether the user has access. | ||
e.g. | ||
```javascript | ||
@@ -182,8 +203,8 @@ app.get('/', function (req, res) { | ||
Inside the views of an express application you may use `user.can` and `user.is` which are equivallent to `req.user.can` and `req.user.is` | ||
Inside the views of an express application you may use `userCan` and `userIs` which are equivallent to `req.userCan` and `req.userIs` | ||
e.g. | ||
e.g. | ||
```html | ||
<% if (user.can('impersonate')) { %> | ||
<% if (userCan('impersonate')) { %> | ||
<button id="impersonate">Impersonate</button> | ||
@@ -193,40 +214,15 @@ <% } %> | ||
**N.B.** not displaying a button doesn't mean someone can't do the thing that the button would do if clicked. The view is not where your security should go, but it is important for useability that you don't display buttons that will just result in 'access denied' where possible. | ||
or in jade: | ||
### roles.setFailureHandler(fn(req, res, action)) | ||
You can (and should) set the failure handler. This is called whenever a user fails authorisation in route middleware. | ||
Defaults to: | ||
```javascript | ||
user.setFailureHandler(function (req, res, action){ | ||
res.send(403); | ||
}); | ||
```jade | ||
if userCan('impersonate') | ||
button#impersonate Impersonate | ||
``` | ||
There is no "next" by design, to stop you accidentally calling it and allowing someone into a restricted part of your site. You are passed the action requested which caused them to be denied access. | ||
**N.B.** not displaying a button doesn't mean someone can't do the thing that the button would do if clicked. The view is not where your security should go, but it is important for useability that you don't display buttons that will just result in 'access denied'. | ||
You could using this to redirect the user or render an error page: | ||
## License | ||
```javascript | ||
user.setFailureHandler(function (req, res, action){ | ||
var accept = req.headers.accept || ''; | ||
res.status(403); | ||
if(req.user.isAuthenticated){ | ||
if (~accept.indexOf('html')) { | ||
res.render('access-denied', {action: action}); | ||
} else { | ||
res.send('Access Denied - You don\'t have permission to: ' + action); | ||
} | ||
} else { | ||
res.redirect('/login'); | ||
} | ||
}); | ||
``` | ||
MIT | ||
## License | ||
MIT | ||
If you find it useful, a payment via [gittip](https://www.gittip.com/ForbesLindesay) would be appreciated. | ||
If you find it useful, a payment via [gittip](https://www.gittip.com/ForbesLindesay) would be appreciated. |
@@ -1,109 +0,192 @@ | ||
var roles = require('../'); | ||
var assert = require('should'); | ||
var assert = require('assert'); | ||
var Roles = require('../'); | ||
function constant(val) { | ||
return function () { | ||
return val; | ||
}; | ||
} | ||
function request(user) { | ||
return { | ||
user: user, | ||
isAuthenticated: constant(user ? true : false) | ||
}; | ||
} | ||
function response() { | ||
return { | ||
locals: {} | ||
}; | ||
} | ||
describe('middleware', function () { | ||
describe('when there is a user', function () { | ||
it('adds methods', function (done) { | ||
var req = {user: { id: 'Forbes' }}; | ||
var res = {}; | ||
roles(req, res, function (err) { | ||
if (err) return done(err); | ||
req.user.isAuthenticated.should.equal(true); | ||
req.user.can.should.be.a('function'); | ||
req.user.is.should.be.a('function'); | ||
done(); | ||
}); | ||
}); | ||
it('adds locals', function (done) { | ||
var req = {user: { id: 'Forbes' }}; | ||
var res = {locals: {}}; | ||
roles(req, res, function (err) { | ||
if (err) return done(err); | ||
req.user.isAuthenticated.should.equal(true); | ||
req.user.can.should.be.a('function'); | ||
req.user.is.should.be.a('function'); | ||
res.locals.user.isAuthenticated.should.equal(true); | ||
res.locals.user.can.should.be.a('function'); | ||
res.locals.user.is.should.be.a('function'); | ||
done(); | ||
}); | ||
}); | ||
describe('when there is a user', function () { | ||
it('adds methods', function (done) { | ||
var roles = new Roles(); | ||
var req = request({ id: 'Forbes' }); | ||
var res = response(); | ||
roles.middleware()(req, res, function (err) { | ||
if (err) return done(err); | ||
assert.strictEqual(typeof req.user.can, 'function'); | ||
assert.strictEqual(typeof req.user.is, 'function'); | ||
assert.strictEqual(req.user.can('foo'), false); | ||
assert.strictEqual(req.user.is('foo'), false); | ||
assert.strictEqual(typeof req.userCan, 'function'); | ||
assert.strictEqual(typeof req.userIs, 'function'); | ||
assert.strictEqual(req.userCan('foo'), false); | ||
assert.strictEqual(req.userIs('foo'), false); | ||
assert.strictEqual(res.locals.isAuthenticated(), true); | ||
assert.strictEqual(typeof res.locals.user.can, 'function'); | ||
assert.strictEqual(typeof res.locals.user.is, 'function'); | ||
assert.strictEqual(res.locals.user.can('foo'), false); | ||
assert.strictEqual(res.locals.user.is('foo'), false); | ||
assert.strictEqual(typeof res.locals.userCan, 'function'); | ||
assert.strictEqual(typeof res.locals.userIs, 'function'); | ||
assert.strictEqual(res.locals.userCan('foo'), false); | ||
assert.strictEqual(res.locals.userIs('foo'), false); | ||
done(); | ||
}); | ||
}); | ||
describe('when there is no user', function () { | ||
it('adds methods and the anonymous user', function (done) { | ||
var req = {}; | ||
var res = {}; | ||
roles(req, res, function (err) { | ||
if (err) return done(err); | ||
req.user.isAuthenticated.should.equal(false); | ||
req.user.can.should.be.a('function'); | ||
req.user.is.should.be.a('function'); | ||
done(); | ||
}); | ||
}); | ||
it('adds locals for the anonymous user', function (done) { | ||
var req = {}; | ||
var res = {locals: {}}; | ||
roles(req, res, function (err) { | ||
if (err) return done(err); | ||
req.user.isAuthenticated.should.equal(false); | ||
req.user.can.should.be.a('function'); | ||
req.user.is.should.be.a('function'); | ||
res.locals.user.isAuthenticated.should.equal(false); | ||
res.locals.user.can.should.be.a('function'); | ||
res.locals.user.is.should.be.a('function'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('when there is no user', function () { | ||
it('adds methods and the anonymous user', function (done) { | ||
var roles = new Roles(); | ||
var req = request(); | ||
var res = response(); | ||
roles.middleware()(req, res, function (err) { | ||
if (err) return done(err); | ||
assert.strictEqual(typeof req.userCan, 'function'); | ||
assert.strictEqual(typeof req.userIs, 'function'); | ||
assert.strictEqual(req.userCan('foo'), false); | ||
assert.strictEqual(req.userIs('foo'), false); | ||
assert.strictEqual(res.locals.isAuthenticated(), false); | ||
assert.strictEqual(typeof res.locals.userCan, 'function'); | ||
assert.strictEqual(typeof res.locals.userIs, 'function'); | ||
assert.strictEqual(res.locals.userCan('foo'), false); | ||
assert.strictEqual(res.locals.userIs('foo'), false); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
function notCalled(name) { | ||
return function notCalled() { | ||
throw new Error('The function ' + name + ' should not be called here.'); | ||
} | ||
return function notCalled() { | ||
throw new Error('The function ' + name + ' should not be called here.'); | ||
} | ||
} | ||
describe('isAuthenticated route middleware', function () { | ||
describe('when there is a user', function () { | ||
before(function () { | ||
roles.setFailureHandler(notCalled('Failure Handler')); | ||
}); | ||
it('passes the test', function (done) { | ||
var req = {user: { isAuthenticated: true }}; | ||
var res = {send: notCalled('send')}; | ||
roles.isAuthenticated(req, res, function (err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
after(function () { | ||
roles.setFailureHandler(function failureHandler(req, res, action) { | ||
res.send(403); | ||
}); | ||
}); | ||
describe('when there is a user', function () { | ||
it('passes the test', function (done) { | ||
var roles = new Roles({ | ||
failureHandler: notCalled('Failure Handler') | ||
}); | ||
var req = request({id: 'Forbes'}); | ||
var res = {send: notCalled('send')}; | ||
roles.isAuthenticated()(req, res, function (err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
describe('when there is a user but they aren\'t authenticated.', function () { | ||
it('fails the test', function (done) { | ||
var req = {user: { id: 'Forbes' }}; | ||
var res = {send: send}; | ||
function send(code) { | ||
code.should.equal(403); | ||
done(); | ||
} | ||
roles.isAuthenticated(req, res, notCalled('next')); | ||
}); | ||
}); | ||
describe('when there is no user.', function () { | ||
it('fails the test', function (done) { | ||
var roles = new Roles(); | ||
function send(code) { | ||
assert.strictEqual(code, 403); | ||
done(); | ||
} | ||
var req = request(); | ||
var res = {send: send}; | ||
roles.isAuthenticated()(req, res, notCalled('next')); | ||
}); | ||
describe('when there is no user', function () { | ||
it('adds methods and the anonymous user', function (done) { | ||
var req = {}; | ||
var res = {}; | ||
roles(req, res, function (err) { | ||
if (err) return done(err); | ||
req.user.isAuthenticated.should.equal(false); | ||
req.user.can.should.be.a('function'); | ||
req.user.is.should.be.a('function'); | ||
done(); | ||
}); | ||
}); | ||
it('calls the failure handler', function (done) { | ||
var roles = new Roles({ | ||
failureHandler: function (request, response, action) { | ||
assert.strictEqual(request, req); | ||
assert.strictEqual(response, res); | ||
assert.strictEqual(action, 'isAuthenticated'); | ||
done(); | ||
} | ||
}); | ||
var req = request(); | ||
var res = {}; | ||
roles.isAuthenticated()(req, res, notCalled('next')); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('can middleware', function () { | ||
describe('when the user is authenticated', function () { | ||
it('passes the test', function (done) { | ||
var roles = new Roles(); | ||
var req = request(); | ||
var res = {}; | ||
roles.use(function (req, action) { assert.strictEqual(action, 'any'); return true; }); | ||
roles.can('any')(req, res, function (err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('when the user is not authenticated', function () { | ||
it('fails the test', function (done) { | ||
var roles = new Roles(); | ||
roles.use(function (req, action) { assert.strictEqual(action, 'any'); return false; }); | ||
function send(code) { | ||
assert.strictEqual(code, 403); | ||
done(); | ||
} | ||
var req = request(); | ||
var res = {send: send}; | ||
roles.can('any')(req, res, notCalled('next')); | ||
}); | ||
it('calls the failure handler', function (done) { | ||
var roles = new Roles({ | ||
failureHandler: function (request, response, action) { | ||
assert.strictEqual(request, req); | ||
assert.strictEqual(response, res); | ||
assert.strictEqual(action, 'any'); | ||
done(); | ||
} | ||
}); | ||
roles.use(function (req, action) { assert.strictEqual(action, 'any'); return false; }); | ||
var req = request(); | ||
var res = {}; | ||
roles.can('any')(req, res, notCalled('next')); | ||
}); | ||
}); | ||
}); | ||
describe('when there are no handlers', function () { | ||
it('requests are rejected by default', function () { | ||
var roles = new Roles(); | ||
assert.strictEqual(roles.test(request(), 'any'), false); | ||
}); | ||
}); | ||
describe('when there are no handlers that return `true` or `false`', function () { | ||
it('requests are rejected by default', function () { | ||
var roles = new Roles(); | ||
var called = false; | ||
roles.use(function (req, action) { assert(action === 'any'); called = true; }); | ||
assert.strictEqual(roles.test(request(), 'any'), false); | ||
assert.strictEqual(called, true); | ||
}); | ||
}); | ||
describe('when the first handler to return a value returns `false`', function () { | ||
it('requests are rejected', function () { | ||
var roles = new Roles(); | ||
roles.use(function (req, action) { assert(action === 'any'); }); | ||
roles.use(function (req, action) { assert(action === 'any'); return false; }); | ||
roles.use(function (req, action) { assert(action === 'any'); return true; }); | ||
assert.strictEqual(roles.test(request(), 'any'), false); | ||
}); | ||
}); | ||
describe('when the first handler to return a value returns `true`', function () { | ||
it('requests are accepted', function () { | ||
var roles = new Roles(); | ||
roles.use(function (req, action) { assert(action === 'any'); }); | ||
roles.use(function (req, action) { assert(action === 'any'); return true; }); | ||
roles.use(function (req, action) { assert(action === 'any'); return false; }); | ||
assert.strictEqual(roles.test(request(), 'any'), true); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
20138
1
347
3
219
1
+ Addedert@1.0.1
+ Addedpromise@~4.0.0
+ Addedasap@1.0.0(transitive)
+ Addedcharacter-parser@1.0.2(transitive)
+ Addedert@1.0.1(transitive)
+ Addedpromise@4.0.0(transitive)
- Removeddebug@0.7.2
- Removeddebug@0.7.2(transitive)