UNPKG

globalstorage

Version:

Global Storage is a Global Distributed Data Warehouse

313 lines (257 loc) 12.6 kB
'use strict'; function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } var metasync = require('metasync'); var _require = require('@metarhia/common'), Uint64 = _require.Uint64; var _require2 = require('./pg.utils'), escapeIdentifier = _require2.escapeIdentifier; var _require3 = require('./utils'), runIf = _require3.runIf; var permissionFlags = { read: 1, insert: 2, update: 4, delete: 8 }; // TODO replace the SQL queries with Cursor usage so that it is not pinned to // Postgres var categoryQuery = function categoryQuery(div) { return "\nSELECT EXISTS (\n SELECT 1 FROM \"SystemUserRoles\" sur\n WHERE \"SystemUser\" = $1 AND\n EXISTS (\n SELECT 1 FROM \"Permission\" perm\n WHERE sur.\"Roles\" = \"Role\" AND\n (SELECT NOT \"Blocked\" FROM \"Role\" WHERE \"Id\" = perm.\"Role\") AND\n \"Category\" = (\n SELECT \"Id\" FROM \"Category\" WHERE \"Name\" = $2\n ) AND \"Access\" & $3 <> 0 ".concat(div ? "AND ".concat(div, " = $4") : '', "\n )\n)"); }; var actionQuery = "\nSELECT EXISTS (\n SELECT 1 FROM \"SystemUserRoles\" sur\n WHERE \"SystemUser\" = $1 AND\n EXISTS (\n SELECT 1 FROM \"Permission\" perm\n WHERE sur.\"Roles\" = \"Role\" AND\n (SELECT NOT \"Blocked\" FROM \"Role\" WHERE \"Id\" = perm.\"Role\") AND\n \"Category\" = (\n SELECT \"Id\" FROM \"Category\" WHERE \"Name\" = $2\n ) AND EXISTS (\n SELECT 1 FROM \"PermissionActions\"\n WHERE \"Permission\" = perm.\"Id\" AND\n \"Actions\" IN (\n SELECT \"Id\" FROM \"Action\" WHERE \"Name\" = $3\n )\n )\n )\n)"; var categoryFilterQuery = "\nSELECT DISTINCT \"Category\".\"Name\" FROM \"Category\"\n INNER JOIN \"Permission\" ON \"Permission\".\"Category\" = \"Category\".\"Id\"\n INNER JOIN (SELECT unnest($2::text[]) \"Name\") \"PossibleCategory\" ON\n \"PossibleCategory\".\"Name\" = \"Category\".\"Name\"\n WHERE \"Permission\".\"Role\" IN (\n SELECT \"Roles\" FROM \"SystemUserRoles\" WHERE \"SystemUser\" = $1\n )"; var categoryPermissionFilterQuery = "\nSELECT \"Category\".\"Name\", bit_or(\"Permission\".\"Access\") \"Flags\" FROM \"Category\"\n INNER JOIN \"Permission\" ON \"Permission\".\"Category\" = \"Category\".\"Id\"\n INNER JOIN (SELECT unnest($2::text[]) \"Name\") \"PossibleCategory\" ON\n \"PossibleCategory\".\"Name\" = \"Category\".\"Name\"\n WHERE \"Permission\".\"Role\" IN (\n SELECT \"Roles\" FROM \"SystemUserRoles\" WHERE \"SystemUser\" = $1\n )\n GROUP BY \"Category\".\"Name\"\n"; var actionFilterQuery = "\nSELECT DISTINCT ON (\"Category\".\"Name\", \"Action\".\"Name\")\n \"Category\".\"Name\" \"Category\", \"Action\".\"Name\" \"Action\" FROM \"Category\"\n INNER JOIN \"Permission\" ON \"Permission\".\"Category\" = \"Category\".\"Id\"\n INNER JOIN \"PermissionActions\" ON\n \"PermissionActions\".\"Permission\" = \"Permission\".\"Id\"\n INNER JOIN \"Action\" ON \"Action\".\"Id\" = \"PermissionActions\".\"Actions\"\n INNER JOIN unnest($2::text[], $3::text[])\n \"SchemaActions\" (\"Category\", \"Action\") ON\n \"SchemaActions\".\"Category\" = \"Category\".\"Name\" AND\n \"SchemaActions\".\"Action\" = \"Action\".\"Name\"\n WHERE \"Permission\".\"Role\" IN (\n SELECT \"Roles\" FROM \"SystemUserRoles\" WHERE \"SystemUser\" = $1\n )"; var applicationFilterQuery = "\nSELECT DISTINCT \"Application\".\"Name\" FROM \"Application\"\n INNER JOIN \"RoleApplications\" ra ON \"Application\".\"Id\" = ra.\"Applications\"\n INNER JOIN (SELECT unnest($2::text[]) \"Name\") \"PossibleApp\" ON\n \"PossibleApp\".\"Name\" = \"Application\".\"Name\"\n WHERE ra.\"Role\" IN (\n SELECT \"Roles\" FROM \"SystemUserRoles\" WHERE \"SystemUser\" = $1\n )"; var checkPermission = function checkPermission(provider, accessType, category, userId, callback) { var flag = permissionFlags[accessType]; provider.pool.query(categoryQuery(), [userId, category, flag], function (err, res) { if (err) { provider.systemLogger(err); callback(err); } else { callback(null, res.rows[0].exists); } }); }; var validateIdString = function validateIdString(id) { return new Uint64(id).toString() === id; }; var validateQuery = function validateQuery(provider, category, query) { var categorySchema = provider.schema.categories.get(category); var catalogField = categorySchema.catalog; if (catalogField && (!query[catalogField] || !validateIdString(query[catalogField]))) { return false; } var subsystemField = categorySchema.subsystem; if (subsystemField && (!query[subsystemField] || !validateIdString(query[subsystemField]))) { return false; } return true; }; var checkPermissionComplex = function checkPermissionComplex(provider, accessType, category, userId, _ref, callback) { var record = _ref.record, id = _ref.id, isPatch = _ref.isPatch, isQuery = _ref.isQuery; var getRecord = function getRecord(category, id, callback) { provider.pool.query("SELECT * FROM ".concat(escapeIdentifier(category), " WHERE \"Id\" = $1"), [id], function (err, res) { if (err) { callback(err); } else { callback(null, res.rows[0]); } }); }; runIf(id, getRecord, category, id, function (err, dbRec) { if (err) { provider.systemLogger(err); callback(err); return; } if (dbRec) record = dbRec; if (!record || isQuery && !validateQuery(provider, category, record)) { callback(null, false); return; } var categorySchema = provider.schema.categories.get(category); var flag = permissionFlags[accessType]; var ops = []; if (categorySchema.catalog) { var catalogValue = record[categorySchema.catalog]; if (!isPatch || catalogValue) { ops.push({ query: categoryQuery(escapeIdentifier('Catalog')), args: [userId, category, flag, catalogValue] }); } } if (categorySchema.subsystem) { var subsystemValue = record[categorySchema.subsystem]; if (!isPatch || subsystemValue) { ops.push({ query: categoryQuery(escapeIdentifier('Subsystem')), args: [userId, category, flag, subsystemValue] }); } } metasync.map(ops, function (op, callback) { provider.pool.query(op.query, op.args, function (err, res) { if (err) { callback(err); } else { callback(null, res.rows[0].exists); } }); }, function (err, res) { if (err) { provider.systemLogger(err); callback(err); } else { callback(null, !res.includes(false)); } }); }); }; var checkExecutePermission = function checkExecutePermission(provider, category, action, userId, callback) { if (category === null) { process.nextTick(callback, null, provider.schema.actions.has(action)); return; } provider.pool.query(actionQuery, [userId, category, action], function (err, res) { if (err) { provider.systemLogger(err); callback(err); return; } callback(null, res.rows[0].exists); }); }; var filterCategories = function filterCategories(provider, categories, userId, callback) { provider.pool.query(categoryFilterQuery, [userId, categories], function (err, res) { if (err) { provider.systemLogger(err); callback(err); return; } callback(null, res.rows.map(function (r) { return r.Name; })); }); }; var filterCategoriesWithPermissions = function filterCategoriesWithPermissions(provider, categories, userId, callback) { provider.pool.query(categoryPermissionFilterQuery, [userId, categories], function (err, res) { if (err) { provider.systemLogger(err); callback(err); return; } var result = {}; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = res.rows[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _step$value = _step.value, Name = _step$value.Name, Flags = _step$value.Flags; result[Name] = String(Flags); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } callback(null, result); }); }; var filterApplications = function filterApplications(provider, applications, userId, callback) { provider.pool.query(applicationFilterQuery, [userId, applications], function (err, res) { if (err) { provider.systemLogger(err); callback(err); return; } callback(null, res.rows.map(function (r) { return r.Name; })); }); }; var filterActions = function filterActions(provider, actions, userId, callback) { var preparedActions = [[], []]; var _arr = Object.entries(actions.private); for (var _i = 0; _i < _arr.length; _i++) { var _preparedActions$; var _arr$_i = _slicedToArray(_arr[_i], 2), cat = _arr$_i[0], acts = _arr$_i[1]; // TODO: replace with common.pushSame() after it becomes available there // See https://github.com/metarhia/common/pull/257 var from = preparedActions[0].length; preparedActions[0].length += acts.length; preparedActions[0].fill(cat, from); (_preparedActions$ = preparedActions[1]).push.apply(_preparedActions$, _toConsumableArray(acts)); } provider.pool.query(actionFilterQuery, [userId].concat(preparedActions), function (err, res) { if (err) { provider.systemLogger(err); callback(err); return; } var result = { public: actions.public, private: {} }; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = res.rows[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var row = _step2.value; if (!result.private[row.Category]) { result.private[row.Category] = [row.Action]; } else { result.private[row.Category].push(row.Action); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return != null) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } callback(null, result); }); }; module.exports = { checkPermission: checkPermission, checkPermissionComplex: checkPermissionComplex, checkExecutePermission: checkExecutePermission, filterCategories: filterCategories, filterCategoriesWithPermissions: filterCategoriesWithPermissions, filterActions: filterActions, filterApplications: filterApplications };