Last active
April 28, 2017 14:37
-
-
Save lkmill/13b0352815b88a22a1c98cb656b1e4c4 to your computer and use it in GitHub Desktop.
authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const _ = require('lodash'); | |
module.exports = (permissions, requiredPermissions) => { | |
if (!_.isPlainObject(requiredPermissions)) { | |
throw new TypeError('`requiredPermissions` is not an object'); | |
} else if (!_.isPlainObject(permissions)) { | |
throw new TypeError('`permissions` is not an object'); | |
} else { | |
for (const key in requiredPermissions) { | |
if (permissions[key] == null || (permissions[key] & requiredPermissions[key] !== requiredPermissions[key])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const _ = require('lodash'); | |
const CRUD = ['create', 'read', 'update', 'delete'].reverse(); | |
// should be in format `entity:number` or `entity:action` or `entity:action1,action2,action3` | |
// a user that can only create has 1000 bits > 8, only delete 0001 > 1, everything 1111 > 15 | |
module.exports = function parsePermissions(permissions) { | |
if (!Array.isArray(permissions)) { | |
permissions = [ permissions ]; | |
} | |
return permissions.reduce((result, str) => { | |
let [ entity, actions ] = str.split(':'); | |
let integer = actions ? +actions : 0; | |
if (!_.isNumber(integer)) { | |
actions = actions.split(',') | |
integer = actions.reduce((result, action) => { | |
const index = CRUD.indexOf(action); | |
if (index < 0) { | |
throw new Error(`Unkown action "${action}"`); | |
} | |
return result & 2^index; | |
}, 0); | |
} | |
if (integer > 0) { | |
result[entity] = integer; | |
} | |
return result; | |
}, {}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const _ = require('lodash'); | |
const compare = require('./compare'); | |
const parsePermissions = require('./util/parse-permissions'); | |
module.exports = (getPermissions, getRequiredPermissions) => { | |
if (!_.isFunction(getPermissions) || !_.isFunction(getRequiredPermissions)) { | |
throw new TypeError('Both parameters need to be functions'); | |
} | |
return { | |
fromReq(req, res, next) { | |
Promise.all([ | |
getPermissions(req), | |
getRequiredPermissions(req), | |
]).then((result) => compare(...result); | |
}).then((authorized) => { | |
if (authorized) return next(); | |
throw new ForbiddenError(); | |
}).catch(next); | |
}, | |
// calls next if user has at least one of the required permissions | |
// `requiredPermissions`should be of format `entity:action` or `entity:action1,action2,action3` | |
all(...requiredPermissions) { | |
if (!requiredPermissions.length) return (req, res, next) => next(); | |
requiredPermissions = parsePermissions(requiredPermissions); | |
return (req, res, next) => { | |
getPermissions(req).then((permissions)) | |
.catch(next); | |
} | |
}, | |
// calls next if user has at least one of the required permissions | |
// `requiredPermissions`should be of format `entity:action` or `entity:action1,action2,action3` | |
any(...requiredPermissions) { | |
requiredPermissions = parsePermissions(requiredPermissions); | |
return (req, res, next) => { | |
getPermissions(req).then((permissions)) | |
.catch(next); | |
} | |
}, | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const _ = require('lodash'); | |
const req = require('http').IncomingMessage.prototype; | |
module.exports = ({ serialize, deserialize }) => { | |
if (!_.isFunction(serialize) || !_.isFunction(deserialize)) { | |
throw new TypeError('Both arguments need to be functions'); | |
} | |
req.login = function (user) { | |
if (!req.session) Promise.reject(new Error('Session middleware not in use')); | |
return serialize(user).then((result) => { | |
req.session.user = result; | |
}).catch((err) => { | |
delete req.sesson.user; | |
throw err; | |
}); | |
} | |
req.logout = function () { | |
delete req.session.user; | |
delete req.user; | |
} | |
req.isAuthenticated = function () { | |
return this.session && this.session.user; | |
} | |
req.isUnauthenticated = function () { | |
return !this.isAuthenticated(); | |
} | |
// option1 | |
req.getUser = function () { | |
if (this.__user) return Promise.resolve(this.__user); | |
if (!req.session || !req.session.user) return Promise.resolve(null); | |
return deserialize(this.session.user).then((user) => { | |
this.__user = user; | |
return user; | |
}); | |
} | |
Object.defineProperty(req, 'user', { | |
get() { | |
if (this.__user) return Promise.resolve(this.__user); | |
if (!req.session || !req.session.user) return Promise.resolve(null); | |
return deserialize(this.session.user).then((user) => { | |
this.__user = user; | |
return user; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment