Skip to content

Instantly share code, notes, and snippets.

@lkmill
Last active April 28, 2017 14:37
Show Gist options
  • Save lkmill/13b0352815b88a22a1c98cb656b1e4c4 to your computer and use it in GitHub Desktop.
Save lkmill/13b0352815b88a22a1c98cb656b1e4c4 to your computer and use it in GitHub Desktop.
authentication
'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;
}
};
'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;
}, {});
};
'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);
}
},
};
};
'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