expacl
Version:
Express Access Control List middleware
94 lines (93 loc) • 4.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var middleware = function (opts) {
var MAX_SUB_VARIANTS = 20;
var route2parsed = function (route) {
var splittedPart = (typeof route.path === 'string') ? route.path.split("/").filter(function (p) { return p.length > 0; }) : [route.path];
return {
path: splittedPart,
pathLen: splittedPart.length,
roles: route.roles ? ((Array.isArray(route.roles) ? route.roles : [route.roles])) : ['*'],
methods: route.methods ?
(Array.isArray(route.methods) ? route.methods.map(function (m) { return m.toLowerCase(); }) :
[route.methods.toLowerCase()]) : ['*'],
action: route.action || opts.defaultAction || 'allow',
};
};
var parsedRouteSubVariants = function (route) {
var arr = [route]
.concat(new Array(MAX_SUB_VARIANTS)
.fill(undefined)
.map(function (_, idx) { return Object.assign({}, route, {
path: route.path.concat(new Array(idx + 1).fill('*')),
pathLen: route.pathLen + idx + 1
}); }));
return arr;
};
var parseRoute = function (route) {
var parsedRoute = route2parsed(route);
if (route.subroutes && route.subroutes.length > 0) {
if (parsedRoute.path[parsedRoute.pathLen - 1] === '*') {
throw new Error('*' + " (any) path route should not have subroutes");
}
var subroutes = parseRoutes(route.subroutes);
return subroutes.map(function (r) {
return {
path: parsedRoute.path.concat(r.path),
pathLen: parsedRoute.pathLen + r.pathLen,
roles: r.roles,
methods: r.methods,
action: r.action,
};
}).concat(route.transient ? [] : [parsedRoute]);
}
else {
return route.transient ? [] : ((parsedRoute.path[parsedRoute.pathLen - 1] === '*') ? parsedRouteSubVariants(parsedRoute) : [parsedRoute]);
}
};
var parseRoutes = function (routes) {
return routes
.map(function (route) { return parseRoute(route); })
.reduce(function (acc, val) { return acc.concat(val); }, []);
};
var routes = parseRoutes(opts.routes);
var _middleware = function (req, res, next) {
var path = (opts.resource ? opts.resource(req) : req.url).split('/').filter(function (p) { return p.length > 0; });
var pathLen = path.length;
var method = req.method.toLowerCase();
var notAllowed = function () {
var authenticated = opts.authenticated || (function (req) { return !!req.user; });
if (authenticated(req)) {
return (opts.onNotAuthorized) ? opts.onNotAuthorized(req, res, next) : res.status(403).send("403 Not authorized");
}
else {
return (opts.onNotAuthenticated) ? opts.onNotAuthenticated(req, res, next) : res.status(401).send("401 Not authenticated");
}
};
var notFound = function () { return (opts.onNotFound) ? opts.onNotFound(req, res, next) : res.status(404).send("404 Not found"); };
var route = routes.find(function (r) {
var shallowCheck = (r.pathLen === pathLen) && (r.methods.includes('*') || r.methods.includes(method));
if (!shallowCheck) {
return false;
}
var pathCheck = r.path.reduce(function (acc, p, idx) {
return acc && ((typeof p === 'string') ? ((p === '*') || (p === path[idx])) : (p.test(path[idx])));
}, true);
return pathCheck;
});
if (!route) {
return (opts.missingRoute != 'allow') ? notFound() : next();
}
if (route.roles.includes('*')) {
return next();
}
var roles = (opts.roles ? opts.roles(req) : (req.user ? req.user.roles : undefined)) || [];
var roleCheck = roles.findIndex(function (r) { return route.roles.includes(r); });
if (roleCheck === -1) {
notAllowed();
}
return next();
};
return _middleware;
};
exports.middleware = middleware;