database-proxy
Version:
Through a set of access control rules configuration database access to realize the client directly access the database via HTTP.
113 lines (112 loc) • 4.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataHandler = void 0;
const types_1 = require("../../types");
const security_1 = require("../../utils/security");
const constraint_1 = require("../../utils/constraint");
const console_1 = require("console");
const DataHandler = async function (config, context) {
// 缺省时,直接通过
if (config === undefined) {
return null;
}
const { data, merge, action } = context.params;
if (!data)
return 'data is undefined';
if (typeof data !== 'object')
return 'data must be an object';
if (action === types_1.ActionType.ADD) {
return await dealAddData(config, context);
}
if (action === types_1.ActionType.UPDATE && merge) {
return await dealUpdateData(config, context);
}
if (action === types_1.ActionType.UPDATE && !merge) {
return await dealAddData(config, context);
}
};
exports.DataHandler = DataHandler;
/**
* 处理 add data
* @param config
* @param context
* @returns
*/
async function dealAddData(config, context) {
const { data } = context.params;
// data in add 不可有操作符
if (security_1.SecurityUtil.hasUpdateOperator(data)) {
return 'data must not contain any operator';
}
const input_fields = Object.keys(data);
if (!input_fields.length)
return 'data is empty';
// 数组代表只允许出现的字段
if (config instanceof Array) {
const allow_fields = config;
const error = security_1.SecurityUtil.isAllowedFields(input_fields, allow_fields);
return error;
}
// 对象则逐一检查字段约束
if (typeof config === 'object') {
const allow_fields = Object.keys(config);
let error = security_1.SecurityUtil.isAllowedFields(input_fields, allow_fields);
if (error)
return error;
const constraint = new constraint_1.Constraint(context, data);
for (const field of allow_fields) {
error = await constraint.constraintField(field, config[field]);
if (error)
return error;
}
return null;
}
return 'config error: config must be an array or object';
}
/**
* 处理 update data
* @param config
* @param context
* @returns
*/
async function dealUpdateData(config, context) {
var _a;
const { data, merge } = context.params;
(0, console_1.assert)(merge, 'merge should be true when perform updating');
const flatten = security_1.SecurityUtil.flattenData(data);
const fields = Object.keys(flatten);
if (!fields.length)
return 'data is empty';
let allow_fields = [];
// 更新时必须有更新操作符,如 $set $push $inc $mul 之类的操作符
if (!security_1.SecurityUtil.hasUpdateOperator(data)) {
return 'data must contain operator while `merge` with true';
}
// 数组代表只允许出现的字段
if (config instanceof Array) {
allow_fields = config;
const error = security_1.SecurityUtil.isAllowedFields(fields, allow_fields);
return error;
}
// 对象则逐一检查字段约束
if (typeof config === 'object') {
allow_fields = Object.keys(config);
let error = security_1.SecurityUtil.isAllowedFields(fields, allow_fields);
if (error)
return error;
// 只对 $set 数据做约束检查
const set_data = (_a = data.$set) !== null && _a !== void 0 ? _a : {};
// 更新时忽略 required 和 default 约束
const constraint = new constraint_1.Constraint(context, set_data, [
constraint_1.ConstraintTypes.REQUIRED,
constraint_1.ConstraintTypes.DEFAULT,
]);
for (const field of allow_fields) {
error = await constraint.constraintField(field, config[field]);
if (error)
return error;
}
return null;
}
return 'config error: config must be an array or object';
}