Socket
Socket
Sign inDemoInstall

cansecurity

Package Overview
Dependencies
79
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.0 to 3.0.1

376

lib/authorization.js
/*jslint node:true, nomen:false, unused:vars */
var errors = require('./errors'), rparams = require('./param'), sender = require('./sender'),
const errors = require('./errors'), rparams = require('./param'), sender = require('./sender'),
constants = require('./constants').get(),
csauth = constants.header.AUTH,
fields = {}, params = {},
checkLoggedIn, checkSelf, checkUserRoles, checkParam, checkField, fns, i, j;
fields = {}, params = {};
checkLoggedIn = function (req, res, next) {
// If our user is authenticated
// then everything is fine :)
var logged = true;
rparams(req);
if (!req[csauth]) {
sender(res,401,errors.unauthenticated());
logged = false;
}
return (logged);
};
checkSelf = function (req, res, next) {
var isSelf = false, userid = (req.params[params.id] || req.body[params.id] || "").toString();
rparams(req);
if (req[csauth][fields.id].toString() === userid) {
isSelf = true;
next();
}
return (isSelf);
};
checkUserRoles = function (req, res, next, roles) {
var userRoles = req[csauth][fields.roles],
isRole = false,
i, targetRoles = {};
rparams(req);
roles = roles || [];
for (i = 0; i < roles.length; i++) {
targetRoles[roles[i]] = true;
}
if (userRoles && userRoles.length && userRoles.length > 0) {
for (i = 0; i < userRoles.length; i++) {
if (targetRoles[userRoles[i]]) {
const checkLoggedIn = (req, res, next) => {
// If our user is authenticated
// then everything is fine :)
let logged = true;
rparams(req);
if (!req[csauth]) {
sender(res,401,errors.unauthenticated());
logged = false;
}
return (logged);
},
checkSelf = function (req, res, next) {
const userid = (req.params[params.id] || req.body[params.id] || "").toString();
let isSelf = false;
rparams(req);
if (req[csauth][fields.id].toString() === userid) {
isSelf = true;
next();
}
return (isSelf);
},
checkUserRoles = (req, res, next, roles) => {
const userRoles = req[csauth][fields.roles], targetRoles = {};
rparams(req);
roles = roles || [];
for (let i of roles) {
targetRoles[i] = true;
}
let isRole = false;
for (let i of userRoles || []) {
if (targetRoles[i]) {
isRole = true;
break;
}

@@ -46,189 +45,156 @@ }

}
}
return (isRole);
};
checkParam = function (req, res, next, param) {
var isParam = false,
id = req[csauth][fields.id],
i;
rparams(req);
param = [].concat(param);
// check the ID of the user against each field in each result for which it is allowed
for (i = 0; i < param.length; i++) {
if (id === req.param(param[i])) {
isParam = true;
break;
return (isRole);
},
checkParam = (req, res, next, param) => {
const id = req[csauth][fields.id];
let isParam = false;
rparams(req);
param = [].concat(param);
// check the ID of the user against each field in each result for which it is allowed
for (let i of param) {
if (id === req.param(i)) {
isParam = true;
break;
}
}
}
if (isParam) {
next();
}
return (isParam);
};
checkField = function (req, res, next, field, getObject) {
var id = req[csauth][fields.id],
i, j, valid, list = [].concat(getObject(req, res) || {});
rparams(req);
// check the ID of the user against each field in each result for which it is allowed, for each object
// *all* must pass to be allowed
for (j = 0; j < list.length; j++) {
valid = false;
for (i = 0; i < field.length; i++) {
if (id === list[j][field[i]]) {
valid = true;
if (isParam) {
next();
}
return (isParam);
},
checkField = (req, res, next, field, getObject) => {
const id = req[csauth][fields.id], list = [].concat(getObject(req, res) || {});
let valid;
rparams(req);
// check the ID of the user against each field in each result for which it is allowed, for each object
// *all* must pass to be allowed
for (let item of list) {
valid = false;
for (let name of field) {
if (id === item[name]) {
valid = true;
break;
}
}
if (!valid) {
break;
}
}
if (!valid) {
break;
if (valid) {
next();
}
}
if (valid) {
next();
}
return (valid);
};
return (valid);
},
fns = {
direct: {
// valid if the user is logged in
restrictToLoggedIn: function (req, res, next) {
// If our user is authenticated
// then everything is fine :)
if (checkLoggedIn(req, res, next)) {
next();
fns = {
direct: {
// valid if the user is logged in
restrictToLoggedIn: (req, res, next) => {
// If our user is authenticated
// then everything is fine :)
checkLoggedIn(req, res, next) && next();
},
// valid if user is logged in *and* the ID if the logged-in user is equal to the ID param
restrictToSelf: (req, res, next) => {
// If our authenticated user is the user we are viewing
// then everything is fine :)
checkLoggedIn(req, res, next) && !checkSelf(req, res, next) && sender(res,403,errors.unauthorized());
}
},
// valid if user is logged in *and* the ID if the logged-in user is equal to the ID param
restrictToSelf: function (req, res, next) {
// If our authenticated user is the user we are viewing
// then everything is fine :)
if (checkLoggedIn(req, res, next)) {
if (!checkSelf(req, res, next)) {
sender(res,403,errors.unauthorized());
indirect: {
// valid if user is logged in *and* the logged-in user has at least one of the given roles
restrictToRoles: (roles) => {
roles = roles ? [].concat(roles) : [];
return (req, res, next) => {
checkLoggedIn(req, res, next) && !checkUserRoles(req, res, next, roles) && sender(res,403,errors.unauthorized());
};
},
// valid if user is logged in *and* the logged-in user is equal to the ID param *or* user has at least one of the given roles
restrictToSelfOrRoles: (roles) => {
roles = roles ? [].concat(roles) : [];
return (req, res, next) => {
checkLoggedIn(req, res, next) &&
!checkSelf(req, res, next) &&
!checkUserRoles(req, res, next, roles) &&
sender(res,403,errors.unauthorized());
};
},
// valid if user is logged in *and* some given field is the same as a given param
restrictToParam: (param) =>
(req, res, next) => {
checkLoggedIn(req, res, next) &&
!checkParam(req, res, next, param) &&
sender(res,403,errors.unauthorized());
}
,
// valid if user is logged in *and* some given field is the same as a given param *or* user has one of the given roles
restrictToParamOrRoles: (param, roles) => {
roles = roles ? [].concat(roles) : [];
param = param ? [].concat(param) : [];
return (req, res, next) => {
// valid if the user name is the same as the param name, or the logged in user is an admin
checkLoggedIn(req, res, next) &&
!checkUserRoles(req, res, next, roles) &&
!checkParam(req, res, next, param) &&
sender(res,403,errors.unauthorized());
};
},
// valid if user is logged in *and* the ID of the logged-in user is equivalent to some field on an arbitrary object
restrictToField: (field, getField) => {
field = field ? [].concat(field) : [];
return (req, res, next) => {
// valid if the user name is the same as the param name, or the logged in user is an admin
checkLoggedIn(req, res, next) &&
!checkField(req, res, next, field, getField) &&
sender(res,403,errors.unauthorized());
};
},
// valid if user is logged in *and* the ID of the logged-in user is equivalent to some field on an arbitrary object *or* user has one of the given roles
restrictToFieldOrRoles: (field, roles, getField) => {
roles = roles ? [].concat(roles) : [];
field = field ? [].concat(field) : [];
return (req, res, next) => {
// valid if the user name is the same as the param name, or the logged in user is an admin
checkLoggedIn(req, res, next) &&
!checkUserRoles(req, res, next, roles) &&
!checkField(req, res, next, field, getField) &&
sender(res,403,errors.unauthorized());
};
}
}
},
indirect: {
// valid if user is logged in *and* the logged-in user has at least one of the given roles
restrictToRoles: function (roles) {
roles = roles ? [].concat(roles) : [];
return function (req, res, next) {
if (checkLoggedIn(req, res, next)) {
if (!checkUserRoles(req, res, next, roles)) {
sender(res,403,errors.unauthorized());
}
}
};
},
// valid if user is logged in *and* the logged-in user is equal to the ID param *or* user has at least one of the given roles
restrictToSelfOrRoles: function (roles) {
roles = roles ? [].concat(roles) : [];
return function (req, res, next) {
if (checkLoggedIn(req, res, next)) {
if (!checkSelf(req, res, next)) {
if (!checkUserRoles(req, res, next, roles)) {
sender(res,403,errors.unauthorized());
ifs: {
// limit our restriction to if a certain param has a certain value
ifParam: (param, val) => {
let that = {};
const
makeMiddleware = (fn) =>
(req, res, next) => {
if ((req.query && req.query[param] === val) || (req.body && req.body[param] === val)) {
fn(req, res, next);
} else {
next();
}
},
makeIndirectMiddleware = (middleware) =>
// this cannot be an arrow function because we use arguments
function () {
return makeMiddleware(middleware.apply(that, arguments));
}
}
}
};
},
// valid if user is logged in *and* some given field is the same as a given param
restrictToParam: function (param) {
return function (req, res, next) {
if (checkLoggedIn(req, res, next)) {
if (!checkParam(req, res, next, param)) {
sender(res,403,errors.unauthorized());
}
}
};
},
// valid if user is logged in *and* some given field is the same as a given param *or* user has one of the given roles
restrictToParamOrRoles: function (param, roles) {
roles = roles ? [].concat(roles) : [];
param = param ? [].concat(param) : [];
return function (req, res, next) {
// valid if the user name is the same as the param name, or the logged in user is an admin
if (checkLoggedIn(req, res, next)) {
if (!checkUserRoles(req, res, next, roles)) {
if (!checkParam(req, res, next, param)) {
sender(res,403,errors.unauthorized());
}
}
}
};
},
// valid if user is logged in *and* the ID of the logged-in user is equivalent to some field on an arbitrary object
restrictToField: function (field, getField) {
field = field ? [].concat(field) : [];
return function (req, res, next) {
// valid if the user name is the same as the param name, or the logged in user is an admin
if (checkLoggedIn(req, res, next)) {
if (!checkField(req, res, next, field, getField)) {
sender(res,403,errors.unauthorized());
}
}
};
},
// valid if user is logged in *and* the ID of the logged-in user is equivalent to some field on an arbitrary object *or* user has one of the given roles
restrictToFieldOrRoles: function (field, roles, getField) {
roles = roles ? [].concat(roles) : [];
field = field ? [].concat(field) : [];
return function (req, res, next) {
// valid if the user name is the same as the param name, or the logged in user is an admin
if (checkLoggedIn(req, res, next)) {
if (!checkUserRoles(req, res, next, roles)) {
if (!checkField(req, res, next, field, getField)) {
sender(res,403,errors.unauthorized());
}
}
}
};
}
},
ifs: {
// limit our restriction to if a certain param has a certain value
ifParam: function (param, val) {
var that = {}, i, j, makeMiddleware, makeIndirectMiddleware;
makeMiddleware = function (fn) {
return function (req, res, next) {
if ((req.query && req.query[param] === val) || (req.body && req.body[param] === val)) {
fn(req, res, next);
} else {
next();
}
};
};
makeIndirectMiddleware = function (middleware) {
return function () {
return makeMiddleware(middleware.apply(that, arguments));
};
};
// wrap the possible return functions
for (i in fns.direct) {
if (fns.direct.hasOwnProperty(i)) {
//makeIndirectMiddleware = (middleware) => () => makeMiddleware(middleware.apply(that, arguments))
;
// wrap the possible return functions
for (let i of Object.keys(fns.direct)) {
that[i] = makeMiddleware(fns.direct[i]);
}
}
for (j in fns.indirect) {
if (fns.indirect.hasOwnProperty(j)) {
that[j] = makeIndirectMiddleware(fns.indirect[j]);
for (let i of Object.keys(fns.indirect)) {
that[i] = makeIndirectMiddleware(fns.indirect[i]);
}
return that;
}
return that;
}
}
};
};
var that = {};
for (i in fns) {
if (fns.hasOwnProperty(i)) {
for (j in fns[i]) {
if (fns[i].hasOwnProperty(j)) {
that[j] = fns[i][j];
}
}
}
const that = {};
for (let i of Object.keys(fns)) {
Object.assign(that,fns[i]);
}

@@ -249,2 +215,2 @@ // pass required configs:

}
};
};

@@ -1,25 +0,23 @@

var constants = {
header : {
USER : 'X-CS-User',
AUTH: 'X-CS-Auth',
AUTHMETHOD : 'X-CS-Auth.method',
AUTHSESSION: 'X-CS-Auth',
CORS: 'Access-Control-Expose-Headers'
},
method: {
CREDENTIALS :"credentials",
TOKEN: "token"
}
const constants = {
header : {
USER : 'X-CS-User',
AUTH: 'X-CS-Auth',
AUTHMETHOD : 'X-CS-Auth.method',
AUTHSESSION: 'X-CS-Auth',
CORS: 'Access-Control-Expose-Headers'
},
method: {
CREDENTIALS :"credentials",
TOKEN: "token"
}
};
module.exports = {
init : function (config) {
if(!config) return;
init : (config) => {
if (!config) {return;}
constants.header.AUTH = config.authHeader || constants.header.AUTH;
constants.header.USER = config.userHeader || constants.header.USER;
},
get: function() {
return constants;
}
};
constants.header.AUTH = config.authHeader || constants.header.AUTH;
constants.header.USER = config.userHeader || constants.header.USER;
},
get: () => constants
};
/*jslint node:true, nomen:true */
var fs = require('fs'),
vm = require('vm'),
_ = require('lodash'),
async = require('async'),
errors = require('./errors'),
sender = require('./sender'),
constants = require('./constants').get(),
csauth = constants.header.AUTH,
/*
* pathRegexp from expressjs https://github.com/visionmedia/express/blob/master/lib/utils.js and modified per our needs
* expressjs was released under MIT license as of this writing
* https://github.com/visionmedia/express/blob/9914a1eb3f7bbe01e3783fa70cb78e02570d7336/LICENSE
*/
pathRegexp = function (path, keys, sensitive, strict) {
if (path && path.toString() === '[object RegExp]') {
return path;
}
if (Array.isArray(path)) {
path = '(' + path.join('|') + ')';
}
path = path.concat(strict ? '' : '/?').replace(/\/\(/g, '(?:/').replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function (_, slash, format, key, capture, optional, star) {
keys.push({
name: key,
optional: !! optional
});
slash = slash || '';
return String(
(optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || ((format && '([^/.]+?)') || '([^/]+?)')) + ')' + (optional || '') + (star ? '(/*)?' : ''));
}).replace(/([\/.])/g, '\\$1').replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
},
pathToFormat = function (path,format) {
var ret = (!format || path.match(/(\/|\.\:\w+\?)$/)) ? path : path + ".:format?";
return(ret);
},
globalLoader;
const fs = require('fs'),
vm = require('vm'),
_ = require('lodash'),
async = require('async'),
errors = require('./errors'),
sender = require('./sender'),
constants = require('./constants').get(),
paramProc = require('./param'),
csauth = constants.header.AUTH,
/*
* pathRegexp from expressjs https://github.com/visionmedia/express/blob/master/lib/utils.js and modified per our needs
* expressjs was released under MIT license as of this writing
* https://github.com/visionmedia/express/blob/9914a1eb3f7bbe01e3783fa70cb78e02570d7336/LICENSE
*/
pathRegexp = (path, keys, sensitive, strict) => {
if (path && path.toString() === '[object RegExp]') {
return path;
}
if (Array.isArray(path)) {
path = '(' + path.join('|') + ')';
}
path = path.concat(strict ? '' : '/?').replace(/\/\(/g, '(?:/').replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function (_, slash, format, key, capture, optional, star) {
keys.push({
name: key,
optional: !! optional
});
slash = slash || '';
return String(
(optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || ((format && '([^/.]+?)') || '([^/]+?)')) + ')' + (optional || '') + (star ? '(/*)?' : ''));
}).replace(/([\/.])/g, '\\$1').replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
},
pathToFormat = (path,format) => (!format || path.match(/(\/|\.\:\w+\?)$/)) ? path : path + ".:format?";
let globalLoader;
module.exports = {
init: function (config) {
globalLoader = (config || {}).loader;
},
loadFile: function (cfile,options) {
var data, routes = {}, fpath, loader, localLoader;
options = options || {};
localLoader = options.loader || {};
// source the config file
/*jslint stupid:true */
data = fs.readFileSync(cfile, "utf8");
/*jslint stupid:false */
data = JSON.parse(data) || {};
// do we have rules?
/* each rule is
* [verb,path,[param,][loggedIn,][loader,]condition]
* [string,string,[object,][boolean,][string,]string]
*/
_.each(data.routes || [], function (rule) {
var entry, verb, keys = [],
re;
rule = rule || [];
if (typeof (rule[2]) !== "object") {
rule.splice(2, 0, null);
}
if (typeof (rule[3]) !== "boolean") {
rule.splice(3, 0, false);
}
if (rule.length < 6) {
rule.splice(4, 0, null);
}
verb = rule[0].toLowerCase();
fpath = pathToFormat(rule[1],options.format);
re = pathRegexp(fpath,keys);
entry = {
verb: verb,
url: rule[1],
param: rule[2],
loggedIn: rule[3],
loader: rule[4],
condition: rule[5],
re: re,
keys: keys
};
routes[verb] = routes[verb] || [];
routes[verb].push(entry);
});
return function (req, res, next) {
// authenticated: false = was not logged in and needed to be, send a 401, else check authorized
// authorized: false = send a 403, else next()
var user = req[csauth],
keys, match, oldParams = req.params;
// make sure there is req.param()
require('./param')(req);
// first check verb, then check route regexp match, then check params
async.each(routes[req.method.toLowerCase()] || [], function (entry, callback) {
var useRule = false, path = typeof(req.path) === "function" ? req.path() : req.path,
checkCondition = function (condition, req, user, item) {
var authorized;
try {
authorized = vm.runInNewContext(condition, {
req: req,
request: req,
user: user,
_: _,
item: item
});
} catch (e) {
authorized = false;
}
return (authorized);
};
keys = {};
// path match check
match = (path || "").match(entry.re);
if (match) {
useRule = true;
// create the important parameters
_.each(entry.keys || [], function (p, i) {
keys[p.name] = match[i + 1];
});
// this is so that req.param() or req.params will work
req.params = keys;
// next check if we use param - will be false unless no param, or param is match
if (entry.param) {
useRule = false;
_.each(entry.param, function (val, key) {
if (val !== null && val !== undefined && req.param(key) === val) {
useRule = true;
}
});
}
if (useRule) {
// did we match the verb+path+param?
// first check the authentication
// authenticated = !entry.loggedIn || !!req[csauth];
if (entry.loggedIn && !req[csauth]) {
callback(401, errors.unauthenticated());
} else {
// next check for the loader
if (entry.loader) {
try {
req.cansecurity = req.cansecurity || {};
loader = localLoader[entry.loader] || globalLoader[entry.loader];
loader(req, res, function (err) {
if (err) {
next(err);
} else if (checkCondition(entry.condition, req, user, (req.cansecurity || {}).item)){
callback();
} else {
callback(403, errors.unauthorized());
}
});
} catch (err) {
callback(500, errors.uninitialized());
}
} else if (checkCondition(entry.condition, req, user)) {
callback();
} else {
callback(403, errors.unauthorized());
}
}
} else {
callback();
}
} else {
callback();
}
}, function (err,msg) {
// now reset req.params
req.params = oldParams;
if (err) {
sender(res,err,msg);
} else {
next();
}
});
};
}
init: (config) => {
globalLoader = (config || {}).loader;
},
loadFile: (cfile,options) => {
options = options || {};
const routes = {}, localLoader = options.loader || {},
// source the config file
/*jslint stupid:true */
data = JSON.parse( fs.readFileSync(cfile, "utf8") ) || {};
/*jslint stupid:false */
// do we have rules?
/* each rule is
* [verb,path,[param,][loggedIn,][loader,]condition]
* [string,string,[object,][boolean,][string,]string]
*/
for (let rule of data.routes || []) {
rule = rule || [];
if (typeof (rule[2]) !== "object") {
rule.splice(2, 0, null);
}
if (typeof (rule[3]) !== "boolean") {
rule.splice(3, 0, false);
}
if (rule.length < 6) {
rule.splice(4, 0, null);
}
const keys = [],
verb = rule[0].toLowerCase(),
fpath = pathToFormat(rule[1],options.format),
re = pathRegexp(fpath,keys),
entry = {
verb: verb,
url: rule[1],
param: rule[2],
loggedIn: rule[3],
loader: rule[4],
condition: rule[5],
re: re,
keys: keys
};
routes[verb] = routes[verb] || [];
routes[verb].push(entry);
}
return (req, res, next) => {
// authenticated: false = was not logged in and needed to be, send a 401, else check authorized
// authorized: false = send a 403, else next()
const user = req[csauth], oldParams = req.params;
// make sure there is req.param()
paramProc(req);
// first check verb, then check route regexp match, then check params
async.each(routes[req.method.toLowerCase()] || [], (entry, callback) => {
let useRule = false;
const path = typeof(req.path) === "function" ? req.path() : req.path,
checkCondition = (condition, req, user, item) => {
var authorized;
try {
authorized = vm.runInNewContext(condition, {
req: req,
request: req,
user: user,
_: _,
item: item
});
} catch (e) {
authorized = false;
}
return (authorized);
},
// path match check
match = (path || "").match(entry.re);
if (match) {
useRule = true;
// create the important parameters
req.params = (entry.keys||[]).reduce((result,val,i) => {
result[val.name] = match[i+1];
return result;
},{});
// next check if we use param - will be false unless no param, or param is match
if (entry.param) {
useRule = false;
for (let key of Object.keys(entry.param)) {
const val = entry.param[key];
if (val !== null && val !== undefined && req.param(key) == val) {
useRule = true;
break;
}
}
}
if (useRule) {
// did we match the verb+path+param?
// first check the authentication
// authenticated = !entry.loggedIn || !!req[csauth];
if (entry.loggedIn && !req[csauth]) {
callback(401, errors.unauthenticated());
} else {
// next check for the loader
if (entry.loader) {
try {
req.cansecurity = req.cansecurity || {};
const loader = localLoader[entry.loader] || globalLoader[entry.loader];
loader(req, res, function (err) {
if (err) {
next(err);
} else if (checkCondition(entry.condition, req, user, (req.cansecurity || {}).item)){
callback();
} else {
callback(403, errors.unauthorized());
}
});
} catch (err) {
callback(500, errors.uninitialized());
}
} else if (checkCondition(entry.condition, req, user)) {
callback();
} else {
callback(403, errors.unauthorized());
}
}
} else {
callback();
}
} else {
callback();
}
}, (err,msg) => {
// now reset req.params
req.params = oldParams;
if (err) {
sender(res,err,msg);
} else {
next();
}
});
};
}
};
/*global module, require, Buffer */
var errors = {
unauthorized: function(msg){ return msg || "unauthorized";},
unauthenticated: function(msg){ return msg || "unauthenticated";},
invalidtoken: function(msg){ return msg || "invalidtoken";},
module.exports = {
unauthorized: (msg) => msg || "unauthorized",
unauthenticated: (msg) => msg || "unauthenticated",
invalidtoken: (msg) => msg || "invalidtoken",
// 409 is a resource conflict - see RFC2616
conflict: function(msg){ return msg || "conflict";},
badRequest: function(msg){ return msg || "badrequest";},
notFound: function(msg){ return msg || "notfound";},
uninitialized: function(msg){ return msg || "uninitialized";},
server: function(msg) {return msg || "";}
conflict: (msg) => msg || "conflict",
badRequest: (msg) => msg || "badrequest",
notFound: (msg) => msg || "notfound",
uninitialized: (msg) => msg || "uninitialized",
server: (msg) => msg || ""
};
module.exports = errors;
/*jslint node:true */
// get the authentication/sessionManager library and the authorization library
var cansec = require('./sessionManager'),
auth = require('./authorization'),
declarative = require('./declarative'),
constants = require('./constants');
const cansec = require('./sessionManager'),
auth = require('./authorization'),
declarative = require('./declarative'),
constants = require('./constants');
module.exports = {
init: function (config) {
var authentication, authorization, ret = {}, i, that = this;
// initialize each part of the library
constants.init(config);
authentication = cansec.init(config);
authorization = auth.init(config);
declarative.init(config);
// merge the two into ret object
// authentication methods
for (i in authentication) {
if (authentication.hasOwnProperty(i)) {
ret[i] = authentication[i];
}
}
// authorization methods
for (i in authorization) {
if (authorization.hasOwnProperty(i)) {
ret[i] = authorization[i];
}
}
// declarative authorization
that.authorizer = ret.authorizer = declarative.loadFile;
that.getAuthMethod = ret.getAuthMethod;
that.getUser = ret.getUser;
return (ret);
}
};
init: (config) => {
const ret = {}, that = this, authentication = cansec.init(config), authorization = auth.init(config);
// initialize each part of the library
constants.init(config);
declarative.init(config);
// merge the two into ret object
// authentication methods
Object.assign(ret,authentication,authorization);
// declarative authorization
that.authorizer = ret.authorizer = declarative.loadFile;
that.getAuthMethod = ret.getAuthMethod;
that.getUser = ret.getUser;
return (ret);
}
};
/*jslint node:true */
module.exports = function (req) {
req.param = function(name, defaultValue){
var params = this.params || {}, body = this.body || {}, query = this.query || {},
ret = defaultValue;
if (params[name] !== null && params[name] !== undefined && params.hasOwnProperty(name)) {
ret = params[name];
} else if (body[name] !== null && body[name] !== undefined) {
ret = body[name];
} else if (query[name] !== null && query[name] !== undefined) {
ret = query[name];
}
return ret;
};
};
module.exports = (req) => {
// leave this as old-style function or restify breaks
req.param = function(name, defaultValue) {
const params = this.params || {}, body = this.body || {}, query = this.query || {};
let ret = defaultValue;
if (params[name] !== null && params[name] !== undefined && params.hasOwnProperty(name)) {
ret = params[name];
} else if (body[name] !== null && body[name] !== undefined) {
ret = body[name];
} else if (query[name] !== null && query[name] !== undefined) {
ret = query[name];
}
return ret;
};
};
/*jslint node:true */
module.exports = function (res,status,body) {
// are we in express or restify?
// in express, arity of res.send() is 1 (just body)
// in restify, arity of res.send() is 3 (code,body,headers)
var l = res.send.length;
if (l === 1) {
res.status(status);
if (body !== undefined && body !== null) {
res.send(body);
} else {
res.end();
}
} else {
res.send(status,body);
}
};
module.exports = (res,status,body) => {
// are we in express or restify?
// in express, arity of res.send() is 1 (just body)
// in restify, arity of res.send() is 3 (code,body,headers)
const l = res.send.length;
if (l === 1) {
res.status(status);
if (body !== undefined && body !== null) {
res.send(body);
} else {
res.end();
}
} else {
res.send(status,body);
}
};
/*global module, require, Buffer, console */
var _ = require( 'lodash' ),
crypto = require( 'crypto' ),
tokenlib = require( './token' ),
util = require('./util'),
now = util.now,
publicMethods, validate, invalidTokenMessage,
errors = require( './errors' ),
sender = require('./sender'),
constants = require( './constants' ).get(),
debug = false,
warn = function (msg) {
if (debug) {
console.error(msg);
}
};
const _ = require( 'lodash' ),
crypto = require( 'crypto' ),
tokenlib = require( './token' ),
util = require('./util'),
errors = require( './errors' ),
sender = require('./sender'),
constants = require( './constants' ).get(),
now = util.now,
warn = function (msg) {
if (debug) {
console.error(msg);
}
};
const AUTHHEADER = constants.header.AUTH,
AUTHMETHODHEADER = constants.header.AUTHMETHOD,
AUTHSESSION = AUTHHEADER,
CORSHEADER = constants.header.CORS,
SESSIONEXPIRY = 15, // minutes
RANDOM_STRING_LENGTH = 60,
/*jslint regexp:true */
MSGRE = /^error (.+)$/;
/*jslint regexp:false */
let validate, invalidTokenMessage, debug = false, sessionExpiry,
encryptHeader = false;
// set up warn on tokenlib
tokenlib.setWarn(warn);
var AUTHHEADER = constants.header.AUTH,
AUTHMETHODHEADER = constants.header.AUTHMETHOD,
AUTHSESSION = AUTHHEADER,
CORSHEADER = constants.header.CORS,
SESSIONEXPIRY = 15, // minutes
sessionExpiry, hasInit = false,
encryptHeader = false,
RANDOM_STRING_LENGTH = 60;
/*jslint regexp:true */
var MSGRE = /^error (.+)$/;
/*jslint regexp:false */
///////////////

@@ -38,9 +40,5 @@ //// UTILS ////

var fnOrNull = function ( f ) {
return ( f && typeof ( f ) === "function" ? f : null );
},
genRandomString = function ( length ) {
return crypto.randomBytes( length )
.toString( 'hex' );
};
const fnOrNull = ( f ) => ( f && typeof ( f ) === "function" ? f : null ),
genRandomString = ( length ) => crypto.randomBytes( length ).toString( 'hex' )
;

@@ -52,52 +50,30 @@

var requestHasBasicAuthCredentials = function ( request ) {
return request.headers.authorization && request.headers.authorization.indexOf( "Basic " ) === 0;
}, getBasicAuthCredentials = function ( request ) {
var header = new Buffer( request.headers.authorization.split( ' ' )[ 1 ], 'base64' )
.toString()
.split( ":" );
if ( header && header.length === 2 ) {
return {
user: header[ 0 ],
password: header[ 1 ]
};
}
return null;
}, getAuthCredentials = function ( req ) {
if ( requestHasBasicAuthCredentials( req ) ) {
return getBasicAuthCredentials( req );
}
return null;
}, appendCORSHeader = function ( response ) {
var existing = response.get( CORSHEADER ) || "";
response.set( CORSHEADER, _.compact( existing.split( /,/ ) )
.concat( [ AUTHHEADER ] )
.join( "," ) );
},
getAuthTokenFromHeaders = function ( req ) {
var header = req.headers.authorization,
authToken = header && header.indexOf("Bearer ") === 0 ? header.split(' ')[1] : null;
const requestHasBasicAuthCredentials = ( request ) => request.headers.authorization && request.headers.authorization.indexOf( "Basic " ) === 0,
getBasicAuthCredentials = ( request ) => {
const header = new Buffer( request.headers.authorization.split( ' ' )[ 1 ], 'base64' )
.toString()
.split( ":" );
if ( header && header.length === 2 ) {
return {
user: header[ 0 ],
password: header[ 1 ]
};
}
return null;
},
getAuthCredentials = ( req ) => requestHasBasicAuthCredentials( req ) ? getBasicAuthCredentials( req ) : null,
appendCORSHeader = ( response ) => {
const existing = response.get( CORSHEADER ) || "";
response.set( CORSHEADER, _.compact( existing.split( /,/ ) )
.concat( [ AUTHHEADER ] )
.join( "," ) );
},
getAuthTokenFromHeaders = ( req ) => {
const header = req.headers.authorization,
authToken = header && header.indexOf("Bearer ") === 0 ? header.split(' ')[1] : null;
return authToken;
/*
if ( !authToken ) {return null;}
return authToken;
};
if ( encryptHeader ) {
authToken = tokenlib.decipher( authToken );
}
var authTokenParts = authToken.split( ':' );
var auth = {
valid: authTokenParts.length >= 2,
token: authToken,
hash: authTokenParts[ 0 ],
user: authTokenParts[ 1 ],
expiry: authTokenParts[ 2 ]
};
return auth;
*/
};
/////////////////

@@ -107,66 +83,66 @@ //// SESSION ////

var setupSessionData = function ( request, user, login, expiry ) {
if ( request.session ) {
request.session[ AUTHSESSION ] = {
user: user,
login: login,
expiry: expiry
};
request.session.touch();
}
},
setupSessionHeaders = function ( request, response, user, login, method, expiry ) {
var userAsJson, header;
request[ AUTHHEADER ] = user || {};
request[ AUTHMETHODHEADER ] = method;
userAsJson = JSON.stringify( request[ AUTHHEADER ] );
header = [
"success",
tokenlib.generate( login, userAsJson, expiry ),
login,
expiry
]; response.header( AUTHHEADER, header.join(" "));
},
removeSessionData = function ( request ) {
if ( request.session ) {
delete request.session[ AUTHSESSION ];
}
},
clearHeaders = function ( response ) {
response.removeHeader( AUTHHEADER );
},
endSession = function ( request, response ) {
removeSessionData( request );
clearHeaders( response );
},
cantStablishSession = function ( req, res, next ) {
endSession( req, res );
next();
},
prepareErrorHeaders = function ( response, message ) {
response.header( AUTHHEADER, "error " + message );
},
endSessionWithErrorMessage = function ( request, response, message ) {
removeSessionData( request );
prepareErrorHeaders( response, message );
},
getSessionDataFromRequest = function ( request ) {
var session = {};
if ( request.session ) {
session.auth = request.session[ AUTHSESSION ] || null;
if ( session.auth ) {
session.user = session.auth.user;
}
}
return session;
},
startSession = function ( config ) {
var req = config.req,
res = config.res,
expiry = now() + sessionExpiry;
const setupSessionData = ( request, user, login, expiry ) => {
if ( request.session ) {
request.session[ AUTHSESSION ] = {
user: user,
login: login,
expiry: expiry
};
request.session.touch();
}
},
setupSessionHeaders = ( request, response, user, login, method, expiry ) => {
const u = user || {}, userAsJson = JSON.stringify(u),
header = [
"success",
tokenlib.generate( login, userAsJson, expiry ),
login,
expiry
];
request[ AUTHHEADER ] = u;
request[ AUTHMETHODHEADER ] = method;
response.header( AUTHHEADER, header.join(" "));
},
removeSessionData = ( request ) => {
if ( request.session ) {
delete request.session[ AUTHSESSION ];
}
},
clearHeaders = ( response ) => {
response.removeHeader( AUTHHEADER );
},
endSession = ( request, response ) => {
removeSessionData( request );
clearHeaders( response );
},
cantStablishSession = ( req, res, next ) => {
endSession( req, res );
next();
},
prepareErrorHeaders = ( response, message ) => {
response.header( AUTHHEADER, "error " + message );
},
endSessionWithErrorMessage = ( request, response, message ) => {
removeSessionData( request );
prepareErrorHeaders( response, message );
},
getSessionDataFromRequest = ( request ) => {
const session = {};
if ( request.session ) {
session.auth = request.session[ AUTHSESSION ] || null;
if ( session.auth ) {
session.user = session.auth.user;
}
}
return session;
},
startSession = ( config ) => {
const req = config.req,
res = config.res,
expiry = now() + sessionExpiry;
appendCORSHeader( res );
setupSessionData( req, config.user, config.login, expiry );
setupSessionHeaders( req, res, config.user, config.login, config.method, expiry );
};
appendCORSHeader( res );
setupSessionData( req, config.user, config.login, expiry );
setupSessionHeaders( req, res, config.user, config.login, config.method, expiry );
};

@@ -180,19 +156,19 @@

var validateCallback = function ( success, user, message, pass ) {
if ( success && user ) {
warn("Successfully validated "+user+" via basic auth");
startSession( {
req: this.req,
res: this.res,
user: user,
login: this.creds.user,
password: pass,
method: constants.method.CREDENTIALS
} );
this.next();
} else {
warn("Failed to validate user via basic auth");
endSessionWithErrorMessage( this.req, this.res, message );
sender(this.res, 401, errors.unauthenticated( message ) );
}
const validateCallback = function( success, user, message, pass ) {
if ( success && user ) {
warn(`Successfully validated ${user} via basic auth`);
startSession( {
req: this.req,
res: this.res,
user: user,
login: this.creds.user,
password: pass,
method: constants.method.CREDENTIALS
} );
this.next();
} else {
warn(`Failed to validate user via basic auth`);
endSessionWithErrorMessage( this.req, this.res, message );
sender(this.res, 401, errors.unauthenticated( message ) );
}
};

@@ -204,89 +180,91 @@

var tryStartSessionWithBasicAuthCredentials = function ( req, res, next ) {
var creds = getAuthCredentials( req );
warn("Try Session with Basic Auth Creds for "+req.url);
if ( creds ) {
warn("Basic Auth Creds found for "+creds.user);
const tryStartSessionWithBasicAuthCredentials = ( req, res, next ) => {
const creds = getAuthCredentials( req );
warn(`Try Session with Basic Auth Creds for ${req.url}`);
if ( creds ) {
warn(`Basic Auth Creds found for ${creds.user}`);
var context = {
req: req,
res: res,
next: next,
creds: creds
};
validate( creds.user, creds.password, validateCallback.bind( context ) );
return true;
}
return false;
},
tryStartWithPreviousSessionData = function ( req, res, next ) {
var session = getSessionDataFromRequest( req ), ret;
warn("Try Session with Previous express session data for "+req.url);
const context = {
req: req,
res: res,
next: next,
creds: creds
};
validate( creds.user, creds.password, validateCallback.bind( context ) );
return true;
}
return false;
},
tryStartWithPreviousSessionData = ( req, res, next ) => {
const session = getSessionDataFromRequest( req );
let ret;
warn(`Try Session with Previous express session data for ${req.url}`);
if ( session.user ) {
warn("Session user found");
if ( session.auth.expiry > now() ) {
warn("Session still valid");
startSession( {
req: req,
res: res,
user: session.user,
login: session.auth.login,
password: session.user.pass
} );
} else {
warn("Session expired");
endSession( req, res );
}
next();
ret = true;
} else {
warn("No previous session user found");
ret = false;
}
if ( session.user ) {
warn(`Session user found`);
if ( session.auth.expiry > now() ) {
warn(`Session still valid`);
startSession( {
req: req,
res: res,
user: session.user,
login: session.auth.login,
password: session.user.pass
} );
} else {
warn(`Session expired`);
endSession( req, res );
}
next();
ret = true;
} else {
warn(`No previous session user found`);
ret = false;
}
return ret;
},
tryStartSessionWithAuthToken = function ( req, res, next ) {
var auth = getAuthTokenFromHeaders( req ), ret, token, login;
warn("Try Session with Auth Token for "+req.url);
if ( auth ) {
warn("Auth Token found");
return ret;
},
tryStartSessionWithAuthToken = ( req, res, next ) => {
const auth = getAuthTokenFromHeaders( req );
let ret, token, login;
warn("Try Session with Auth Token for "+req.url);
if ( auth ) {
warn(`Auth Token found`);
// first validate the token
token = tokenlib.validate( auth );
// first validate the token
token = tokenlib.validate( auth );
// if succeeded, then we need to validate the user from the DB
if ( token ) {
login = token.sub;
warn("Successfully validated "+login+" via auth token");
// if succeeded, then we need to validate the user from the DB
if ( token ) {
login = token.sub;
warn(`Successfully validated ${login} via auth token`);
if ( validate ) {
warn("Trying to check user ...");
validate( token.sub, undefined, function (success, user ) {
warn("Tried validation, success? "+success);
if (success) {
startSession( {
req: req,
res: res,
user: user,
login: login,
method: constants.method.TOKEN
} );
next();
}
} );
}
} else {
warn("Failed to validate "+login+" via auth token");
endSessionWithErrorMessage( req, res, errors.invalidtoken( invalidTokenMessage ) );
sender(res, 401, errors.invalidtoken( invalidTokenMessage ) );
}
ret = true;
} else {
warn("No auth token found");
ret = false;
}
return ret;
};
if ( validate ) {
warn(`Trying to check user ...`);
validate( token.sub, undefined, function (success, user ) {
warn(`Tried validation, success? ${success}`);
if (success) {
startSession( {
req: req,
res: res,
user: user,
login: login,
method: constants.method.TOKEN
} );
next();
}
} );
}
} else {
warn(`Failed to validate ${login} via auth token`);
endSessionWithErrorMessage( req, res, errors.invalidtoken( invalidTokenMessage ) );
sender(res, 401, errors.invalidtoken( invalidTokenMessage ) );
}
ret = true;
} else {
warn(`No auth token found`);
ret = false;
}
return ret;
};

@@ -299,41 +277,35 @@

publicMethods = {
// if there is a login session token, refresh its timeout on each request, and validate it
validate: function ( req, res, next ) {
"use strict";
return tryStartSessionWithBasicAuthCredentials( req, res, next ) ||
tryStartWithPreviousSessionData( req, res, next ) ||
tryStartSessionWithAuthToken( req, res, next ) ||
cantStablishSession( req, res, next );
},
clear: endSession,
message: function ( res ) {
var msg, p = res.headers ? ( res.headers[ AUTHHEADER ] || res.headers[ AUTHHEADER.toLowerCase() ] || "" ) : "",
match = MSGRE.exec( p );
const publicMethods = {
// if there is a login session token, refresh its timeout on each request, and validate it
validate: ( req, res, next ) => {
"use strict";
return tryStartSessionWithBasicAuthCredentials( req, res, next ) ||
tryStartWithPreviousSessionData( req, res, next ) ||
tryStartSessionWithAuthToken( req, res, next ) ||
cantStablishSession( req, res, next );
},
clear: endSession,
message: ( res ) => {
const p = res.headers ? ( res.headers[ AUTHHEADER ] || res.headers[ AUTHHEADER.toLowerCase() ] || "" ) : "",
match = MSGRE.exec( p ),
msg = match && match.length > 1 && match[ 1 ].length > 0 ? match[ 1 ] : "";
msg = match && match.length > 1 && match[ 1 ].length > 0 ? match[ 1 ] : "";
return ( msg );
},
getAuthMethod: function ( req ) {
return ( req ? req[ AUTHMETHODHEADER ] : null );
},
getUser: function ( req ) {
if ( req ) {
return req[ AUTHHEADER ];
}
return null;
}
return ( msg );
},
getAuthMethod: ( req ) => ( req ? req[ AUTHMETHODHEADER ] : null ),
getUser: ( req ) => req ? req[ AUTHHEADER ] : null
};
module.exports = {
init: function ( config ) {
validate = fnOrNull( config.validate );
invalidTokenMessage = config.invalidTokenMessage || null;
sessionExpiry = ( config.expiry || SESSIONEXPIRY ) * 60 * 1000;
encryptHeader = ( config.encryptHeader || false );
tokenlib.init( config.sessionKey || genRandomString( RANDOM_STRING_LENGTH ), encryptHeader );
debug = config.debug || false;
hasInit = true;
return publicMethods;
}
init: ( config ) => {
validate = fnOrNull( config.validate );
invalidTokenMessage = config.invalidTokenMessage || null;
sessionExpiry = ( config.expiry || SESSIONEXPIRY ) * 60 * 1000;
encryptHeader = ( config.encryptHeader || false );
debug = config.debug || false;
tokenlib.init( config.sessionKey || genRandomString( RANDOM_STRING_LENGTH ), encryptHeader );
return publicMethods;
}
};

@@ -1,66 +0,56 @@

var crypto = require('crypto'), exports = module.exports, jwt = require('jsonwebtoken');
const crypto = require('crypto'), jwt = require('jsonwebtoken'), now = require('./util').now;
var sessionKey = null;
var encryptHeader = false;
// for safety
var warn = function () {
};
var now = require('./util').now;
let sessionKey = null, encryptHeader = false, warn = () => {};
exports.init = function(key, encrypt) {
sessionKey = key;
encryptHeader = encrypt || false;
};
exports.setWarn = function (fn) {
warn = fn;
};
exports.generate = function(name, user, expiry) {
var token = jwt.sign({sub:name,exp:expiry,"cs-user":user},sessionKey,{algorithm:"HS256"});
module.exports = {
init : (key, encrypt) => {
sessionKey = key;
encryptHeader = encrypt || false;
},
setWarn : (fn) => {
warn = fn;
},
if(encryptHeader) {
token = exports.cipher(token);
}
generate : (name, user, expiry) => {
const token = jwt.sign({sub:name,exp:expiry,"cs-user":user},sessionKey,{algorithm:"HS256"});
return(token);
};
return(encryptHeader ? module.exports.cipher(token) : token);
},
exports.validate = function(token) {
warn("validating auth token "+token);
var valid = false, expiry, decoded, t = now();
token = token || "";
if (encryptHeader) {
token = exports.decipher(token);
}
try {
decoded = jwt.verify(token,sessionKey,{algorithms:"HS256"});
expiry = decoded.exp;
warn("token expiry "+expiry+" now "+t);
warn("token name "+decoded.sub);
if (!isNaN(expiry) && parseInt(expiry,10) > t) {
valid = decoded;
} else {
valid = false;
}
} catch (e) {
valid = false;
}
validate : (token) => {
warn(`validating auth token ${token}`);
const t = now();
let valid = false, expiry, decoded;
token = token || "";
if (encryptHeader) {
token = module.exports.decipher(token);
}
try {
decoded = jwt.verify(token,sessionKey,{algorithms:"HS256"});
expiry = decoded.exp;
warn(`token expiry ${expiry} now ${t}`);
warn(`token name ${decoded.sub}`);
if (!isNaN(expiry) && parseInt(expiry,10) > t) {
valid = decoded;
} else {
valid = false;
}
} catch (e) {
valid = false;
}
warn("token valid? "+valid);
return(decoded);
};
warn(`token valid? ${valid}`);
return(decoded);
},
exports.cipher = function(token) {
var cipher = crypto.createCipher('rc4-hmac-md5', sessionKey);
token = cipher.update(token, 'utf8','base64');
token += cipher.final('base64');
return token;
};
cipher : (token) => {
const cipher = crypto.createCipher('rc4-hmac-md5', sessionKey);
return cipher.update(token, 'utf8','base64') + cipher.final('base64');
},
exports.decipher = function(token){
var decipher = crypto.createDecipher('rc4-hmac-md5', sessionKey);
token = decipher.update(token, 'base64','utf8');
token += decipher.final('utf8');
return token;
decipher : (token) => {
const decipher = crypto.createDecipher('rc4-hmac-md5', sessionKey);
return decipher.update(token, 'base64','utf8') + decipher.final('utf8');
}
};
module.exports = {
now: function () {
return Math.floor(Date.now()/1000);
}
};
now: () => Math.floor(Date.now()/1000)
};
{
"name": "cansecurity",
"description": "cansecurity is your all-in-one security library for user authentication, authorization and management in node expressjs apps",
"version": "3.0.0",
"version": "3.0.1",
"license": "MIT",

@@ -6,0 +6,0 @@ "url": "http://github.com/deitch/cansecurity",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc