database-proxy
Version:
Through a set of access control rules configuration database access to realize the client directly access the database via HTTP.
122 lines (121 loc) • 4.23 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseQueryURI = exports.executeScript = void 0;
const vm = __importStar(require("vm"));
/**
* 用于各场景下的 condition 表达式执行,支持 get() 函数
* @param code js code
* @param objects 要注入执行环境的对象
* @param context 请求上下文
* @param defaultField 当前上下文可指定的字段,用于 query 或 data 验证字段
* @returns
*/
async function executeScript(code, objects, context, defaultField) {
try {
objects = objects !== null && objects !== void 0 ? objects : {};
const { params, ruler } = context;
const global = Object.assign({}, objects);
/**
* 获取代码里可能出现的 get() 函数
* 因 get() 是异步的,无法直接执行,所以提前获取其调用位置和参数
*/
const queries = getQueries(code, global);
// 逐个调用代码中的 get() 函数,并保存其返回结果
const prepared = [];
for (const query of queries) {
const [value, target] = query;
let { collection, field } = parseQueryURI(target);
// 缺省时查当前请求的集合
if (!collection)
collection = params.collection;
if (!field)
field = defaultField !== null && defaultField !== void 0 ? defaultField : '_id';
const result = await doGetQuery(collection, field, value, ruler.accessor);
prepared.push({ query, result });
}
// 构造 get() 函数
function GetFunc(target, value) {
for (const el of prepared) {
const [v, t] = el.query;
if (t === target && v === value)
return el.result;
}
return null;
}
global.get = GetFunc;
const script = new vm.Script(code);
const result = script.runInNewContext(global);
return { result };
}
catch (error) {
return { error };
}
}
exports.executeScript = executeScript;
/**
* 解析查询路径
* @param target target like '/users/_id' or `users/_id` or `_id` or undefined
* @param defaultCollection
* @param defaultField
* @returns
*/
function parseQueryURI(target) {
if (!target) {
return {};
}
const arr = target.split('/');
if (arr.length === 1) {
return { field: arr[0] };
}
if (arr.length === 2) {
return { collection: arr[0], field: arr[1] };
}
if (arr.length === 3) {
return { collection: arr[1], field: arr[2] };
}
}
exports.parseQueryURI = parseQueryURI;
async function doGetQuery(collection, field, value, accessor) {
const query = {
[field]: value,
};
const result = await accessor.get(collection, query);
return result;
}
function getQueries(code, injections) {
const wrapper = `
const __arr = []
function get(...params){
__arr.push(params)
return {}
}
${code};
(__arr);
`;
const script = new vm.Script(wrapper);
const queries = script.runInNewContext(injections);
return queries;
}