globalstorage
Version:
Global Storage is a Global Distributed Data Warehouse
313 lines (257 loc) • 12.6 kB
JavaScript
'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('/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
};