修改了checker和auth的逻辑(未放开)

This commit is contained in:
Xu Chang 2023-01-17 19:58:15 +08:00
parent bd8fd47df5
commit c1eae2142f
11 changed files with 162 additions and 58 deletions

View File

@ -2,14 +2,13 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDynamicCheckers = void 0;
var tslib_1 = require("tslib");
var checker_1 = require("../store/checker");
var modi_1 = require("../store/modi");
function createDynamicCheckers(schema, authDict) {
var checkers = [];
checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, modi_1.createModiRelatedCheckers)(schema)), false));
if (authDict) {
checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createAuthCheckers)(schema, authDict)), false));
}
/* if (authDict) {
checkers.push(...createAuthCheckers<ED, Cxt>(schema, authDict));
} */
return checkers;
}
exports.createDynamicCheckers = createDynamicCheckers;

View File

@ -36,11 +36,11 @@ var TriggerExecutor = /** @class */ (function () {
var trigger = {
checkerType: type,
name: triggerName,
priority: checker.priority || 2,
priority: checker.priority || 20,
entity: entity,
action: action,
fn: fn,
when: 'before',
when: checker.when || 'before',
filter: conditionalFilter,
};
this.registerTrigger(trigger);
@ -59,7 +59,7 @@ var TriggerExecutor = /** @class */ (function () {
throw new Error("\u4E0D\u53EF\u6709\u540C\u540D\u7684\u89E6\u53D1\u5668\u300C".concat(trigger.name, "\u300D"));
}
if (typeof trigger.priority !== 'number') {
trigger.priority = 1; // 默认最低
trigger.priority = 10; // 默认值
}
if (trigger.filter) {
(0, assert_1.default)(typeof trigger.action === 'string' && trigger.action !== 'create'

View File

@ -413,9 +413,9 @@ function translateActionAuthFilterMaker(schema, relationItem, entity) {
function createAuthCheckers(schema, authDict) {
var checkers = [];
var _loop_1 = function (entity) {
var _a, _b;
var _a;
if (authDict[entity]) {
var _c = authDict[entity], relationAuth = _c.relationAuth, actionAuth = _c.actionAuth;
var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth;
if (relationAuth) {
var raFilterMakerDict_1 = {};
for (var r in relationAuth) {
@ -440,7 +440,7 @@ function createAuthCheckers(schema, authDict) {
var filter = raFilterMakerDict_1[relation](userId);
return {
entity: entity,
filter: filter,
filter: (0, filter_1.combineFilters)([filter, { id: entityId }]),
expr: {
$gt: [{
'#attr': '$$createAt$$',
@ -493,36 +493,58 @@ function createAuthCheckers(schema, authDict) {
// todo 等实现的时候再写
}
if (actionAuth) {
var aaFilterMakerDict = {};
for (var a in actionAuth) {
Object.assign(aaFilterMakerDict, (_b = {},
_b[a] = translateActionAuthFilterMaker(schema, actionAuth[a], entity),
_b));
var _loop_2 = function (a) {
var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity);
if (a === 'create') {
/**
* create动作所增加的auth约束只可能在外键的对象上所以需要对此外键对象进行查找
* create动作所增加的auth约束只可能在外键的对象上但因为还有级联和触发器不太容易在创建前检查先放在创建后
*/
var _d = actionAuth[a];
/* checkers.push({
entity,
var _c = actionAuth[a];
checkers.push({
entity: entity,
action: a,
type: 'expressionRelation',
expression: (operation, context) => {
// create要保证数据的外键指向关系满足filter的约束因为这行还没有插入所以要
}
}); */
when: 'after',
expression: function (operation, context) {
// 在插入后检查
var makeExprInner = function (data) {
var id = data.id;
return {
entity: entity,
filter: (0, filter_1.combineFilters)([filter, { id: id }]),
expr: {
$gt: [{
'#attr': '$$createAt$$',
}, 0]
},
};
};
var filter = filterMaker(context.getCurrentUserId());
var data = operation.data;
if (data instanceof Array) {
throw new Error('需要expr支持count');
}
return makeExprInner(data);
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
}
else {
/* checkers.push({
entity,
checkers.push({
entity: entity,
action: a,
type: 'relation',
relationFilter: (operation, context) => {
const { filter } = operation;
}
}); */
relationFilter: function (operation, context) {
// const { filter } = operation;
var filter = filterMaker(context.getCurrentUserId());
return filter;
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
}
};
for (var a in actionAuth) {
_loop_2(a);
}
}
}

2
lib/types/Auth.d.ts vendored
View File

@ -47,6 +47,7 @@ export declare type ExpressionTaskCombination<ED extends EntityDict> = Expressio
export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expression';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;
@ -56,6 +57,7 @@ export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED,
export declare type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expressionRelation';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;

View File

@ -122,7 +122,23 @@ interface GeoDistance<A> {
$distance: [RefOrExpression<A> | Geo, RefOrExpression<A> | Geo];
}
declare type GeoExpression<A> = GeoContains<A> | GeoDistance<A>;
export declare type Expression<A> = GeoExpression<A> | DateExpression<A> | LogicExpression<A> | BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A>;
interface AggrCountExpression<A> {
$$count: RefOrExpression<A>;
}
interface AggrSumExpression<A> {
$$sum: RefOrExpression<A>;
}
interface AggrMaxExpression<A> {
$$max: RefOrExpression<A>;
}
interface AggrMinExpression<A> {
$$min: RefOrExpression<A>;
}
interface AggrAvgExpression<A> {
$$avg: RefOrExpression<A>;
}
export declare type AggrExpression<A> = AggrAvgExpression<A> | AggrCountExpression<A> | AggrSumExpression<A> | AggrMaxExpression<A> | AggrMinExpression<A>;
export declare type Expression<A> = GeoExpression<A> | DateExpression<A> | LogicExpression<A> | BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A> | AggrExpression<A>;
export declare type ExpressionConstant = Geo | number | Date | string | boolean;
export declare function isGeoExpression<A>(expression: any): expression is GeoExpression<A>;
export declare function isDateExpression<A>(expression: any): expression is DateExpression<A>;
@ -131,6 +147,7 @@ export declare function isBoolExpression<A>(expression: any): expression is Bool
export declare function isCompareExpression<A>(expression: any): expression is CompareExpression<A>;
export declare function isMathExpression<A>(expression: any): expression is MathExpression<A>;
export declare function isStringExpression<A>(expression: any): expression is StringExpression<A>;
export declare function isAggrExpression<A>(expression: any): expression is AggrExpression<A>;
export declare function isExpression<A>(expression: any): expression is Expression<A>;
export declare function opMultipleParams(op: string): boolean;
export declare function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isStringExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0;
exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isAggrExpression = exports.isStringExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var dayjs_1 = tslib_1.__importDefault(require("dayjs"));
@ -42,6 +42,7 @@ dayjs_1.default.extend(dayOfYear_1.default);
;
;
;
;
function isGeoExpression(expression) {
if (Object.keys(expression).length == 1) {
var op = Object.keys(expression)[0];
@ -115,6 +116,16 @@ function isStringExpression(expression) {
return false;
}
exports.isStringExpression = isStringExpression;
function isAggrExpression(expression) {
if (Object.keys(expression).length == 1) {
var op = Object.keys(expression)[0];
if (['$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op)) {
return true;
}
}
return false;
}
exports.isAggrExpression = isAggrExpression;
function isExpression(expression) {
return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$');
}
@ -122,7 +133,7 @@ exports.isExpression = isExpression;
function opMultipleParams(op) {
return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth',
'$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs',
'$round', '$floor', '$ceil'].includes(op);
'$round', '$floor', '$ceil', '$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op);
}
exports.opMultipleParams = opMultipleParams;
function execOp(op, params, obscure) {

View File

@ -8,8 +8,8 @@ import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDef, AuthDefD
export function createDynamicCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>, authDict?: AuthDefDict<ED>){
const checkers: Checker<ED, keyof ED, Cxt>[] = [];
checkers.push(...createModiRelatedCheckers<ED, Cxt>(schema));
if (authDict) {
/* if (authDict) {
checkers.push(...createAuthCheckers<ED, Cxt>(schema, authDict));
}
} */
return checkers;
}

View File

@ -4,7 +4,7 @@ import { addFilterSegment, checkFilterRepel } from "../store/filter";
import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity";
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { Logger } from "../types/Logger";
import { Checker, CheckerType } from '../types/Auth';
import { Checker, CheckerType, ExpressionChecker, RelationChecker } from '../types/Auth';
import { Trigger, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn, SelectTriggerAfter, UpdateTrigger } from "../types/Trigger";
import { AsyncContext } from './AsyncRowStore';
import { SyncContext } from './SyncRowStore';
@ -53,11 +53,11 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict> {
const trigger = {
checkerType: type,
name: triggerName,
priority: checker.priority || 2, // checker的默认优先级稍高一点点
priority: checker.priority || 20, // checker的默认优先级稍高
entity,
action: action as 'update',
fn,
when: 'before',
when: (checker as ExpressionChecker<ED, T, Cxt>).when || 'before',
filter: conditionalFilter,
} as UpdateTrigger<ED, T, Cxt>;
this.registerTrigger(trigger);
@ -77,7 +77,7 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict> {
throw new Error(`不可有同名的触发器「${trigger.name}`);
}
if (typeof trigger.priority !== 'number') {
trigger.priority = 1; // 默认最低
trigger.priority = 10; // 默认值
}
if ((trigger as UpdateTrigger<ED, T, Cxt>).filter) {
assert(typeof trigger.action === 'string' && trigger.action !== 'create'

View File

@ -398,7 +398,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
const filter = raFilterMakerDict[relation]!(userId!);
return {
entity,
filter,
filter: combineFilters([filter, { id: entityId }]),
expr: {
$gt: [{
'#attr': '$$createAt$$',
@ -458,36 +458,54 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
}
if (actionAuth) {
const aaFilterMakerDict = {} as Record<string, (suserId: string) => ED[keyof ED]['Selection']['filter']>;
for (const a in actionAuth) {
Object.assign(aaFilterMakerDict, {
[a]: translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity),
});
const filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity);
if (a === 'create') {
/**
* create动作所增加的auth约束只可能在外键的对象上
* create动作所增加的auth约束只可能在外键的对象上
*/
const { } = actionAuth[a as ED[keyof ED]['Action']]!;
/* checkers.push({
checkers.push({
entity,
action: a,
type: 'expressionRelation',
when: 'after',
expression: (operation, context) => {
// create要保证数据的外键指向关系满足filter的约束因为这行还没有插入所以要
}
}); */
// 在插入后检查
const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => {
const { id } = data;
return {
entity,
filter: combineFilters([filter, { id }]),
expr: {
$gt: [{
'#attr': '$$createAt$$',
}, 0] as any
},
};
};
const filter = filterMaker(context.getCurrentUserId()!);
const { data } = operation as ED[keyof ED]['Create'];
if (data instanceof Array) {
throw new Error('需要expr支持count');
}
return makeExprInner(data);
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
}
else {
/* checkers.push({
checkers.push({
entity,
action: a,
action: a as ED[keyof ED]['Action'],
type: 'relation',
relationFilter: (operation, context) => {
const { filter } = operation;
}
}); */
// const { filter } = operation;
const filter = filterMaker(context.getCurrentUserId()!);
return filter;
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
}
}
}

View File

@ -62,6 +62,7 @@ export type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED
export type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expression';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(
@ -76,6 +77,7 @@ export type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt ext
export type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expressionRelation';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(

View File

@ -154,8 +154,31 @@ interface GeoDistance<A> {
type GeoExpression<A> = GeoContains<A> | GeoDistance<A>;
//// Aggr
interface AggrCountExpression<A> {
$$count: RefOrExpression<A>;
};
interface AggrSumExpression<A> {
$$sum: RefOrExpression<A>;
}
interface AggrMaxExpression<A> {
$$max: RefOrExpression<A>;
}
interface AggrMinExpression<A> {
$$min: RefOrExpression<A>;
}
interface AggrAvgExpression<A> {
$$avg: RefOrExpression<A>;
}
export type AggrExpression<A> = AggrAvgExpression<A> | AggrCountExpression<A> | AggrSumExpression<A> | AggrMaxExpression<A> | AggrMinExpression<A>;
export type Expression<A> = GeoExpression<A> | DateExpression<A> | LogicExpression<A>
| BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A>;
| BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A> | AggrExpression<A>;
export type ExpressionConstant = Geo | number | Date | string | boolean;
@ -233,6 +256,16 @@ export function isStringExpression<A>(expression: any): expression is StringExpr
return false;
}
export function isAggrExpression<A>(expression: any): expression is AggrExpression<A> {
if (Object.keys(expression).length == 1) {
const op = Object.keys(expression)[0];
if (['$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op)) {
return true;
}
}
return false;
}
export function isExpression<A>(expression: any): expression is Expression<A> {
return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$');
}
@ -240,7 +273,7 @@ export function isExpression<A>(expression: any): expression is Expression<A> {
export function opMultipleParams(op: string) {
return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth',
'$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs',
'$round', '$floor', '$ceil'].includes(op);
'$round', '$floor', '$ceil', '$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op);
}
export function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant {