UNPKG

security-koa

Version:

security-koa

472 lines (471 loc) 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function handleToken(res, secret, name, t, verify, buildErr) { if (t.error) { res.status(401).end(t.error); return Promise.resolve({ error: t.error, end: true }); } else { return verify(t.token, secret).then(function (payload) { res.locals[name] = payload; return Promise.resolve({ payload: payload, token: t.token }); }).catch(function (err) { var _a = buildErr(err), status = _a.status, body = _a.body; res.status(status).end(body); return Promise.resolve({ token: t.token, error: t.error, end: true }); }); } } exports.handleToken = handleToken; function fromCookies(req, name) { if (!req.cookies) { return { token: '', error: "Require cookies" }; } else { var token = req.cookies[name]; if (!token) { return { token: '', error: "Require '" + name + "' in cookies" }; } else { return { token: token }; } } } exports.fromCookies = fromCookies; function fromAuthorization(req, prefix) { var data = req.headers['authorization']; if (data) { if (!data.startsWith(prefix)) { return { token: '', error: "Authorization must start with '" + prefix.trim() + "'" }; } else { var token = data.substr(prefix.length); return { token: token }; } } else { return { token: '', error: "Require 'Authorization' in header" }; } } exports.fromAuthorization = fromAuthorization; var LocalsToken = (function () { function LocalsToken(token) { this.token = (token ? token : 'token'); this.getToken = this.getToken.bind(this); } LocalsToken.prototype.getToken = function (req, res) { var payload = res.locals[this.token]; return Promise.resolve({ payload: payload }); }; return LocalsToken; }()); exports.LocalsToken = LocalsToken; var CookiesToken = (function () { function CookiesToken(secret, verify, buildErr, payload, token) { this.secret = secret; this.verify = verify; this.token = (token ? token : 'token'); this.payload = (payload ? payload : 'token'); this.buildError = (buildErr ? buildErr : buildError); this.getToken = this.getToken.bind(this); } CookiesToken.prototype.getToken = function (req, res) { var t = fromCookies(req, this.token); return handleToken(res, this.secret, this.payload, t, this.verify, this.buildError); }; return CookiesToken; }()); exports.CookiesToken = CookiesToken; var AuthorizationToken = (function () { function AuthorizationToken(secret, verify, buildErr, payload, prefix) { this.secret = secret; this.verify = verify; this.prefix = (prefix ? prefix : 'Bearer '); this.payload = (payload ? payload : 'token'); this.buildError = (buildErr ? buildErr : buildError); this.getToken = this.getToken.bind(this); } AuthorizationToken.prototype.getToken = function (req, res) { var t = fromAuthorization(req, this.prefix); return handleToken(res, this.secret, this.payload, t, this.verify, this.buildError); }; return AuthorizationToken; }()); exports.AuthorizationToken = AuthorizationToken; var TokenService = (function () { function TokenService(secret, verify, buildErr, payload, token, prefix) { this.secret = secret; this.verify = verify; this.prefix = (prefix ? prefix : 'Bearer '); this.token = (token ? token : 'token'); this.payload = (payload ? payload : 'token'); this.buildError = (buildErr ? buildErr : buildError); this.getToken = this.getToken.bind(this); } TokenService.prototype.getToken = function (req, res) { var t = fromCookies(req, this.token); if (t.error) { t = fromAuthorization(req, this.prefix); } return handleToken(res, this.secret, this.payload, t, this.verify, this.buildError); }; return TokenService; }()); exports.TokenService = TokenService; function useToken(secret, verify, buildErr, cookie, payload, token, prefix) { if (cookie === true) { return new CookiesToken(secret, verify, buildErr, payload, token).getToken; } else if (cookie === false) { return new AuthorizationToken(secret, verify, buildErr, payload, prefix).getToken; } else { return new TokenService(secret, verify, buildErr, payload, token, prefix).getToken; } } exports.useToken = useToken; exports.getToken = useToken; var Handler = (function () { function Handler(secret, verify, prefix, token, payload) { this.secret = secret; this.verify = verify; this.prefix = (prefix ? prefix : 'Bearer '); this.token = (token ? token : 'token'); this.payload = (payload ? payload : 'token'); this.handle = this.handle.bind(this); } Handler.prototype.handle = function () { var _this = this; return function (req, res, next) { var t = fromCookies(req, _this.token); if (t.error) { t = fromAuthorization(req, _this.prefix); } if (t.error) { next(); } else { _this.verify(t.token, _this.secret).then(function (payload) { res.locals[_this.payload] = payload; next(); }).catch(function (err) { next(); }); } }; }; return Handler; }()); exports.Handler = Handler; exports.AuthorizationHandler = Handler; var AuthorizationChecker = (function () { function AuthorizationChecker(gt) { this.getToken = gt; this.check = this.check.bind(this); this.require = this.require.bind(this); } AuthorizationChecker.prototype.require = function () { var _this = this; return function (req, res, next) { _this.getToken(req, res).then(function (t) { if (!t.end) { next(); } }); }; }; AuthorizationChecker.prototype.check = function () { return this.require(); }; return AuthorizationChecker; }()); exports.AuthorizationChecker = AuthorizationChecker; function exist(obj, arr) { if (Array.isArray(obj)) { for (var _i = 0, obj_1 = obj; _i < obj_1.length; _i++) { var o = obj_1[_i]; for (var _a = 0, arr_1 = arr; _a < arr_1.length; _a++) { var v = arr_1[_a]; if (o == v) { return true; } } } } else { for (var _b = 0, arr_2 = arr; _b < arr_2.length; _b++) { var v = arr_2[_b]; if (obj == v) { return true; } } } return false; } exports.exist = exist; var Checker = (function () { function Checker(gt, key) { this.getToken = gt; this.key = (key ? key : 'id'); this.check = this.check.bind(this); } Checker.prototype.check = function (v) { var _this = this; return function (req, res, next) { _this.getToken(req, res).then(function (t) { if (!t.end) { if (t.payload) { var obj = t.payload[_this.key]; if (!obj) { res.status(403).end('Payload must contain ' + _this.key); } else { if (exist(obj, v)) { next(); } else { res.status(403).end('invalid ' + _this.key); } } } else { res.status(403).end('Payload cannot be undefined'); } } }); }; }; return Checker; }()); exports.Checker = Checker; var MultiAuthorizer = (function () { function MultiAuthorizer(gt, privilege, buildErr, key, user, exact) { this.privilege = privilege; this.getToken = gt; this.buildError = (buildErr ? buildErr : buildError); this.user = (user ? user : 'id'); this.key = (key ? key : 'userType'); this.exact = (exact !== undefined ? exact : true); this.authorize = this.authorize.bind(this); } MultiAuthorizer.prototype.authorize = function (v, privilege, action) { var _this = this; return function (req, res, next) { _this.getToken(req, res).then(function (t) { if (!t.end) { if (t.payload) { var obj = t.payload[_this.key]; if (!obj) { res.status(403).end('Payload must contain ' + _this.key); } else { if (exist(obj, v)) { var userId_1 = t.payload[_this.user]; if (!userId_1) { res.status(403).end('Payload must contain ' + _this.user); } else { _this.privilege(userId_1, privilege).then(function (p) { if (p === exports.none) { res.status(403).end('no permission for ' + userId_1); } else { if (!action) { next(); } else { if (_this.exact) { var sum = action & p; if (sum === action) { return next(); } else { res.status(403).end('no permission'); } } else { if (p >= action) { return next(); } else { res.status(403).end('no permission'); } } } } }).catch(function (err) { var _a = _this.buildError(err), status = _a.status, body = _a.body; res.status(status).end(body); }); } } else { res.status(403).end('invalid ' + _this.key); } } } else { res.status(401).end('Payload cannot be undefined'); } } }); }; }; return MultiAuthorizer; }()); exports.MultiAuthorizer = MultiAuthorizer; var Authorizer = (function () { function Authorizer(gt, privilege, buildErr, exact, key) { this.privilege = privilege; this.getToken = gt; this.buildError = (buildErr ? buildErr : buildError); this.key = (key ? key : 'id'); this.exact = (exact !== undefined ? exact : true); this.authorize = this.authorize.bind(this); } Authorizer.prototype.authorize = function (privilege, action) { var _this = this; return function (req, res, next) { _this.getToken(req, res).then(function (t) { if (!t.end) { var payload = t.payload; if (payload === undefined) { res.status(401).end('Payload cannot be undefined'); } else { var userId_2 = payload[_this.key]; if (!userId_2) { res.status(403).end('Payload must contain ' + _this.key); } else { _this.privilege(userId_2, privilege).then(function (p) { if (p === exports.none) { res.status(403).end('no permission for ' + userId_2); } else { if (!action) { next(); } else { if (_this.exact) { var sum = action & p; if (sum === action) { return next(); } else { res.status(403).end('no permission'); } } else { if (p >= action) { return next(); } else { res.status(403).end('no permission'); } } } } }).catch(function (err) { var _a = _this.buildError(err), status = _a.status, body = _a.body; res.status(status).end(body); }); } } } }); }; }; return Authorizer; }()); exports.Authorizer = Authorizer; exports.none = 0; exports.read = 1; exports.write = 2; exports.approve = 4; exports.all = 2147483647; var PrivilegeLoader = (function () { function PrivilegeLoader(sql, query) { this.sql = sql; this.query = query; this.privilege = this.privilege.bind(this); } PrivilegeLoader.prototype.privilege = function (userId, privilegeId) { return this.query(this.sql, [userId, privilegeId]).then(function (v) { if (!v || v.length === 0) { return exports.none; } var keys = Object.keys(v[0]); if (keys.length === 0) { return exports.all; } var k = keys[0]; var permissions = 0; var ok = false; for (var _i = 0, v_1 = v; _i < v_1.length; _i++) { var p = v_1[_i]; var x = p[k]; if (typeof x === 'number') { permissions = permissions | x; ok = true; } } return (ok ? permissions : exports.all); }); }; return PrivilegeLoader; }()); exports.PrivilegeLoader = PrivilegeLoader; function buildError(err) { return { status: 401, body: 'Invalid token: ' + toString(err) }; } exports.buildError = buildError; function toString(err) { return (typeof err === 'string' ? err : JSON.stringify(err)); } exports.toString = toString; function get(app, path, authorize, handle, secure) { if (secure) { app.get(path, authorize, handle); } else { app.get(path, handle); } } exports.get = get; function post(app, path, authorize, handle, secure) { if (secure) { app.post(path, authorize, handle); } else { app.post(path, handle); } } exports.post = post; function put(app, path, authorize, handle, secure) { if (secure) { app.put(path, authorize, handle); } else { app.put(path, handle); } } exports.put = put; function patch(app, path, authorize, handle, secure) { if (secure) { app.patch(path, authorize, handle); } else { app.patch(path, handle); } } exports.patch = patch; function del(app, path, authorize, handle, secure) { if (secure) { app.delete(path, authorize, handle); } else { app.delete(path, handle); } } exports.del = del;