oak-domain/lib/store/checker.js

392 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRelationHierarchyCheckers = exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var filter_1 = require("../store/filter");
var Exception_1 = require("../types/Exception");
var actionDef_1 = require("./actionDef");
var string_1 = require("../utils/string");
function translateCheckerInAsyncContext(checker) {
var _this = this;
var entity = checker.entity, type = checker.type;
switch (type) {
case 'data': {
var checkerFn_1 = checker.checker;
return (function (_a, context) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var data;
return tslib_1.__generator(this, function (_b) {
data = operation.data;
checkerFn_1(data, context);
return [2 /*return*/, 0];
});
});
});
}
case 'row': {
var filter_2 = checker.filter, errMsg_1 = checker.errMsg, inconsistentRows_1 = checker.inconsistentRows;
return (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var operationFilter, action, filter2, entity2, selection2, rows2, data_1, rows2, data_2;
var _b, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0:
operationFilter = operation.filter, action = operation.action;
filter2 = typeof filter_2 === 'function' ? filter_2(operation, context, option) : filter_2;
if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 1];
operation.filter = (0, filter_1.addFilterSegment)(operationFilter || {}, filter2);
return [2 /*return*/, 0];
case 1: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {})];
case 2:
if (_d.sent()) {
return [2 /*return*/, 0];
}
if (!inconsistentRows_1) return [3 /*break*/, 4];
entity2 = inconsistentRows_1.entity, selection2 = inconsistentRows_1.selection;
return [4 /*yield*/, context.select(entity2, selection2(operationFilter), {
dontCollect: true,
blockTrigger: true,
})];
case 3:
rows2 = _d.sent();
data_1 = {};
rows2.forEach(function (ele) {
var _a;
return Object.assign(data_1, (_a = {},
_a[ele.id] = ele,
_a));
});
throw new Exception_1.OakRowInconsistencyException({
a: 's',
d: (_b = {},
_b[entity2] = data_1,
_b)
}, errMsg_1);
case 4: return [4 /*yield*/, context.select(entity, {
data: (0, actionDef_1.getFullProjection)(entity, context.getSchema()),
filter: Object.assign({}, operationFilter, {
$not: filter2,
})
}, {
dontCollect: true,
blockTrigger: true,
})];
case 5:
rows2 = _d.sent();
data_2 = {};
rows2.forEach(function (ele) {
var _a;
return Object.assign(data_2, (_a = {},
_a[ele.id] = ele,
_a));
});
throw new Exception_1.OakRowInconsistencyException({
a: 's',
d: (_c = {},
_c[entity] = data_2,
_c)
}, errMsg_1);
}
});
});
});
}
case 'relation': {
var relationFilter_1 = checker.relationFilter;
return (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_b) {
if (context.isRoot()) {
return [2 /*return*/, 0];
}
// 对后台而言将生成的relationFilter加到filter之上(select可以在此加以权限的过滤)
operation.filter = (0, filter_1.combineFilters)([operation.filter, relationFilter_1(operation, context, option)]);
return [2 /*return*/, 0];
});
});
});
}
case 'expression':
case 'expressionRelation': {
var expression_1 = checker.expression, errMsg_2 = checker.errMsg;
return (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var exprResult, expressionEntity, expr, expressionFilter, _b, result;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
if (context.isRoot() && type === 'expressionRelation') {
return [2 /*return*/, 0];
}
exprResult = expression_1(operation, context, option);
if (!(typeof exprResult === 'string')) return [3 /*break*/, 1];
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2);
case 1:
if (!(exprResult === undefined)) return [3 /*break*/, 2];
return [2 /*return*/, 0];
case 2:
expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
return [4 /*yield*/, context.select(expressionEntity, {
data: {
$expr: expr,
},
filter: expressionFilter,
}, Object.assign({}, option, { dontCollect: true }))];
case 3:
_b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0];
if (!result) {
// 条件判定为假,抛异常
throw new Exception_1.OakUserUnpermittedException(errMsg_2);
}
_c.label = 4;
case 4: return [2 /*return*/, 0];
}
});
});
});
}
default: {
(0, assert_1.default)(false);
}
}
}
exports.translateCheckerInAsyncContext = translateCheckerInAsyncContext;
function translateCheckerInSyncContext(checker) {
var entity = checker.entity, type = checker.type;
switch (type) {
case 'data': {
var checkerFn_2 = checker.checker;
return function (operation, context) { return checkerFn_2(operation.data, context); };
}
case 'row': {
var filter_3 = checker.filter, errMsg_3 = checker.errMsg;
return function (operation, context, option) {
var operationFilter = operation.filter, action = operation.action;
var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3;
(0, assert_1.default)(operationFilter);
if (['select', 'count', 'stat'].includes(action)) {
operation.filter = (0, filter_1.addFilterSegment)(operationFilter, filter2);
return 0;
}
else {
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) {
return;
}
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3);
}
};
}
case 'relation': {
var filter_4 = checker.relationFilter, errMsg_4 = checker.errMsg;
return function (operation, context, option) {
if (context.isRoot()) {
return;
}
var filter2 = typeof filter_4 === 'function' ? filter_4(operation, context, option) : filter_4;
var operationFilter = operation.filter;
(0, assert_1.default)(operationFilter);
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) {
return;
}
throw new Exception_1.OakUserUnpermittedException(errMsg_4);
};
}
case 'expression':
case 'expressionRelation': {
var expression_2 = checker.expression, errMsg_5 = checker.errMsg;
return function (operation, context, option) {
if (context.isRoot() && type === 'expressionRelation') {
return;
}
var exprResult = expression_2(operation, context, option);
if (typeof exprResult === 'string') {
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_5);
}
else if (exprResult === undefined) {
return 0;
}
else {
var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
var _a = tslib_1.__read(context.select(expressionEntity, {
data: {
$expr: expr,
},
filter: expressionFilter,
}, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0];
if (!result.$expr) {
// 条件判定为假,抛异常
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5);
}
return;
}
};
}
default: {
(0, assert_1.default)(false);
}
}
}
exports.translateCheckerInSyncContext = translateCheckerInSyncContext;
function createRelationHierarchyCheckers(schema) {
var checkers = [];
var _loop_1 = function (entity) {
var e_1, _a;
var relationHierarchy = schema[entity].relationHierarchy;
if (relationHierarchy) {
// 先build反向hierarchy的map
var reverseHierarchy_1 = {};
for (var r in relationHierarchy) {
try {
for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) {
var r2 = _c.value;
if (!reverseHierarchy_1[r2]) {
reverseHierarchy_1[r2] = [r];
}
else {
reverseHierarchy_1[r2].push(r);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
}
// 对userEntity对象的授权和回收建立checker
var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity));
var entityIdAttr_1 = "".concat(entity, "Id");
checkers.push({
entity: userEntityName_1,
action: 'create',
type: 'expressionRelation',
expression: function (operation, context) {
var _a;
var data = operation.data;
var _b = data, relation = _b.relation, _c = entityIdAttr_1, entityId = _b[_c];
var legalRelations = reverseHierarchy_1[relation];
if (!legalRelations) {
return undefined;
}
if (legalRelations.length === 0) {
return '这是不应该跑出来的情况,请杀程序员祭天';
}
var userId = context.getCurrentUserId();
return {
entity: userEntityName_1,
expr: {
$gt: [{
'#attr': '$$createAt$$',
}, 0]
},
filter: (_a = {
userId: userId
},
_a[entityIdAttr_1] = entityId,
_a.relation = {
$in: legalRelations,
},
_a)
};
},
errMsg: '越权操作',
});
var _loop_2 = function (r) {
checkers.push({
entity: userEntityName_1,
action: 'remove',
type: 'expressionRelation',
conditionalFilter: {
relation: r,
},
expression: function (operation, context) {
var _a, _b;
var userId = context.getCurrentUserId();
var filter = operation.filter;
var legalRelations = reverseHierarchy_1[r];
if (legalRelations.length === 0) {
return '这是不应该跑出来的情况,请杀程序员祭天';
}
return {
entity: userEntityName_1,
expr: {
$gt: [{
'#attr': '$$createAt$$',
}, 0]
},
filter: (_a = {
userId: userId
},
_a[entityIdAttr_1] = {
$in: {
entity: userEntityName_1,
data: (_b = {},
_b[entityIdAttr_1] = 1,
_b),
filter: filter,
}
},
_a.relation = {
$in: legalRelations,
},
_a),
};
},
errMsg: '越权操作',
});
};
for (var r in reverseHierarchy_1) {
_loop_2(r);
}
/* // 一个人不能授权给自己,也不能删除自己的授权
checkers.push({
entity: userEntityName as keyof ED,
action: 'create' as ED[keyof ED]['Action'],
type: 'data',
checker: (data, context) => {
assert(!(data instanceof Array));
const { userId } = data as ED[keyof ED]['CreateSingle']['data'];
const userId2 = context.getCurrentUserId(true);
if (userId === userId2) {
throw new OakDataException('不允许授权给自己');
}
}
});
checkers.push({
entity: userEntityName as keyof ED,
action: 'remove' as ED[keyof ED]['Action'],
type: 'row',
filter: (operation, context) => {
const userId = context.getCurrentUserId(true);
if (userId) {
return {
userId: {
$ne: userId,
},
};
}
console.warn(`没有当前用户但在删除权限,请检查。对象是${entity}`);
return {};
},
errMsg: '不允许回收自己的授权',
}); */
// 转让权限现在用update动作只允许update userId给其它人
// todo 等实现的时候再写
}
};
for (var entity in schema) {
_loop_1(entity);
}
return checkers;
}
exports.createRelationHierarchyCheckers = createRelationHierarchyCheckers;