@flowerforce/flower-core 4.0.1-beta.1 → 4.0.1-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/index.cjs.js +102 -21
- package/dist/index.esm.js +95 -22
- package/dist/src/ABAC/abacEngine.d.ts +32 -0
- package/dist/src/ABAC/abacSingleton.d.ts +8 -0
- package/dist/src/ABAC/index.d.ts +2 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/interfaces/CoreInterface.d.ts +13 -20
- package/dist/src/interfaces/ReducerInterface.d.ts +7 -5
- package/dist/src/interfaces/RulesMatcherInterface.d.ts +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
## 3.5.2 (2025-04-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### 🩹 Fixes
|
|
5
|
+
|
|
6
|
+
- fix init nodes ([996d8af](https://github.com/flowerforce/flower/commit/996d8af))
|
|
7
|
+
|
|
8
|
+
- package lock ([a3bb210](https://github.com/flowerforce/flower/commit/a3bb210))
|
|
9
|
+
|
|
10
|
+
## 3.5.1 (2025-04-19)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### 🩹 Fixes
|
|
14
|
+
|
|
15
|
+
- remove empty object from init state ([8604346](https://github.com/flowerforce/flower/commit/8604346))
|
|
16
|
+
|
|
17
|
+
## 3.5.0 (2025-04-19)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### 🚀 Features
|
|
21
|
+
|
|
22
|
+
- remove data blank from init nodes ([#80](https://github.com/flowerforce/flower/pull/80))
|
|
23
|
+
|
|
24
|
+
## 3.4.0 (2025-04-19)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### 🚀 Features
|
|
28
|
+
|
|
29
|
+
- added remove value on hide element ([#68](https://github.com/flowerforce/flower/pull/68))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### 🩹 Fixes
|
|
33
|
+
|
|
34
|
+
- avoid validate hidden field ([#67](https://github.com/flowerforce/flower/pull/67))
|
|
35
|
+
|
|
1
36
|
## 3.3.0 (2024-10-08)
|
|
2
37
|
|
|
3
38
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -62,6 +62,89 @@ const generateData = (data) => {
|
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
class AbacEngine {
|
|
66
|
+
constructor(rules = []) {
|
|
67
|
+
// compile string conditions once
|
|
68
|
+
this.rules = (rules || [])
|
|
69
|
+
.map((r) => {
|
|
70
|
+
let conditionFn = undefined;
|
|
71
|
+
if (r.condition) {
|
|
72
|
+
try {
|
|
73
|
+
// NOTE: uses new Function -> ensure rules.json is trusted by the app owner
|
|
74
|
+
conditionFn = new Function('subject', 'resource', 'action', 'environment', `return (${r.condition});`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error('ABAC: failed to compile rule condition', r.id, err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { ...r, conditionFn };
|
|
81
|
+
})
|
|
82
|
+
.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
83
|
+
}
|
|
84
|
+
decide(ctx) {
|
|
85
|
+
let anyPermit = false;
|
|
86
|
+
for (const r of this.rules) {
|
|
87
|
+
const matchesAction = Array.isArray(r.action)
|
|
88
|
+
? r.action.includes(ctx.action)
|
|
89
|
+
: r.action === ctx.action || r.action === '*';
|
|
90
|
+
if (!matchesAction)
|
|
91
|
+
continue;
|
|
92
|
+
let matches = true;
|
|
93
|
+
if (r.conditionFn) {
|
|
94
|
+
try {
|
|
95
|
+
matches = !!r.conditionFn(ctx.subject, ctx.resource, ctx.action, ctx.environment);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
matches = false;
|
|
99
|
+
console.error(`ABAC: rule ${r.id} threw while evaluating`, err);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!matches)
|
|
103
|
+
continue;
|
|
104
|
+
if (r.effect === 'Deny') {
|
|
105
|
+
// deny-overrides
|
|
106
|
+
return 'Deny';
|
|
107
|
+
}
|
|
108
|
+
if (r.effect === 'Permit') {
|
|
109
|
+
anyPermit = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return anyPermit ? 'Permit' : 'Deny';
|
|
113
|
+
}
|
|
114
|
+
// utility: checks multiple actions and returns those allowed
|
|
115
|
+
allowedActions(ctxBase, actions) {
|
|
116
|
+
return actions.filter((a) => this.decide({ ...ctxBase, action: a }) === 'Permit');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let engine = null;
|
|
121
|
+
let rawRules = null;
|
|
122
|
+
let currentSubject = null;
|
|
123
|
+
function initAbac(rules) {
|
|
124
|
+
engine = new AbacEngine(rules);
|
|
125
|
+
rawRules = rules;
|
|
126
|
+
}
|
|
127
|
+
function getAbacEngine() {
|
|
128
|
+
if (!engine)
|
|
129
|
+
console.warn('ABAC engine non inizializzato');
|
|
130
|
+
return engine;
|
|
131
|
+
}
|
|
132
|
+
function getRawRules() {
|
|
133
|
+
return rawRules;
|
|
134
|
+
}
|
|
135
|
+
function isAbacInitialized() {
|
|
136
|
+
return engine !== null;
|
|
137
|
+
}
|
|
138
|
+
function setSubject(subject) {
|
|
139
|
+
currentSubject = subject;
|
|
140
|
+
}
|
|
141
|
+
function getSubject() {
|
|
142
|
+
return currentSubject;
|
|
143
|
+
}
|
|
144
|
+
function clearSubject() {
|
|
145
|
+
currentSubject = null;
|
|
146
|
+
}
|
|
147
|
+
|
|
65
148
|
const EMPTY_STRING_REGEXP = /^\s*$/;
|
|
66
149
|
/**
|
|
67
150
|
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
|
@@ -85,6 +168,11 @@ const rulesMatcherUtils = {
|
|
|
85
168
|
if (!operators[op]) {
|
|
86
169
|
throw new Error(`Error missing operator:${op}`);
|
|
87
170
|
}
|
|
171
|
+
if (op === '$can') {
|
|
172
|
+
const subject = getSubject();
|
|
173
|
+
const valid = operators['$can'](subject ?? {}, _get(value, 'action'), _get(value, 'resource'));
|
|
174
|
+
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
175
|
+
}
|
|
88
176
|
const valid = operators[op] && operators[op](valueForKey, valueRef, opt, data);
|
|
89
177
|
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
90
178
|
},
|
|
@@ -242,6 +330,11 @@ const rulesMatcherUtils = {
|
|
|
242
330
|
* Defines a set of comparison operators used for matching rules against user input.
|
|
243
331
|
*/
|
|
244
332
|
const operators = {
|
|
333
|
+
$can: (subject, action, resource) => getAbacEngine()?.decide({
|
|
334
|
+
subject: subject ?? {},
|
|
335
|
+
action,
|
|
336
|
+
resource
|
|
337
|
+
}) === 'Permit',
|
|
245
338
|
$exists: (a, b) => !rulesMatcherUtils.isEmpty(a) === b,
|
|
246
339
|
$eq: (a, b) => a === b,
|
|
247
340
|
$ne: (a, b) => a !== b,
|
|
@@ -304,9 +397,6 @@ const flattenRules = (ob) => {
|
|
|
304
397
|
}
|
|
305
398
|
return result;
|
|
306
399
|
};
|
|
307
|
-
const getRulesExists = (rules) => {
|
|
308
|
-
return Object.keys(rules).length ? FlowUtils.mapEdge(rules) : undefined;
|
|
309
|
-
};
|
|
310
400
|
const FlowUtils = {
|
|
311
401
|
generateRulesName: (nextRules) => {
|
|
312
402
|
return nextRules.reduce((acc, inc) => {
|
|
@@ -363,23 +453,6 @@ const FlowUtils = {
|
|
|
363
453
|
return res;
|
|
364
454
|
},
|
|
365
455
|
makeRules: (rules) => Object.entries(rules).reduce((acc2, [k, v]) => [...acc2, { nodeId: k, rules: v }], []),
|
|
366
|
-
// TODO: This function is strictly related to React nodes, could make sense to move it in the flower-react folder
|
|
367
|
-
generateNodesForFlowerJson: (nodes) => nodes
|
|
368
|
-
.filter((e) => !!_get(e, 'props.id'))
|
|
369
|
-
.map((e) => {
|
|
370
|
-
const rules = FlowUtils.makeRules(e.props.to ?? {});
|
|
371
|
-
const nextRules = getRulesExists(rules);
|
|
372
|
-
const children = e.props.data?.children;
|
|
373
|
-
return {
|
|
374
|
-
nodeId: e.props.id,
|
|
375
|
-
nodeType: e.type.displayName || e.props.as || 'FlowerNode',
|
|
376
|
-
nodeTitle: _get(e.props, 'data.title'),
|
|
377
|
-
children,
|
|
378
|
-
nextRules,
|
|
379
|
-
retain: e.props.retain,
|
|
380
|
-
disabled: e.props.disabled
|
|
381
|
-
};
|
|
382
|
-
}),
|
|
383
456
|
allEqual: (arr, arr2) => arr.length === arr2.length && arr.every((v) => arr2.includes(v)),
|
|
384
457
|
findValidRule: (nextRules, value, prefix) => find(nextRules, (rule) => {
|
|
385
458
|
// fix per evitare di entrare in un nodo senza regole, ma con un name,
|
|
@@ -650,7 +723,7 @@ const FlowerCoreBaseReducers = {
|
|
|
650
723
|
payload: { name: flowName, node: nextNumberNode }
|
|
651
724
|
});
|
|
652
725
|
},
|
|
653
|
-
|
|
726
|
+
back: (state, { payload }) => {
|
|
654
727
|
const { name, flowName } = payload;
|
|
655
728
|
FlowerCoreBaseReducers.historyPop(state, {
|
|
656
729
|
type: 'historyPop',
|
|
@@ -843,6 +916,7 @@ const FlowerCoreStateSelectors = {
|
|
|
843
916
|
...FlowerCoreStateDataSelectors
|
|
844
917
|
};
|
|
845
918
|
|
|
919
|
+
exports.AbacEngine = AbacEngine;
|
|
846
920
|
exports.CoreUtils = CoreUtils;
|
|
847
921
|
exports.DataUtils = DataUtils;
|
|
848
922
|
exports.Emitter = Emitter;
|
|
@@ -854,8 +928,15 @@ exports.FlowerCoreStateBaseSelectors = FlowerCoreStateBaseSelectors;
|
|
|
854
928
|
exports.FlowerCoreStateDataSelectors = FlowerCoreStateDataSelectors;
|
|
855
929
|
exports.FlowerCoreStateSelectors = FlowerCoreStateSelectors;
|
|
856
930
|
exports.FlowerStateUtils = FlowerStateUtils;
|
|
931
|
+
exports.clearSubject = clearSubject;
|
|
857
932
|
exports.devtoolState = devtoolState;
|
|
858
933
|
exports.flattenRules = flattenRules;
|
|
859
934
|
exports.generateData = generateData;
|
|
935
|
+
exports.getAbacEngine = getAbacEngine;
|
|
936
|
+
exports.getRawRules = getRawRules;
|
|
937
|
+
exports.getSubject = getSubject;
|
|
938
|
+
exports.initAbac = initAbac;
|
|
939
|
+
exports.isAbacInitialized = isAbacInitialized;
|
|
860
940
|
exports.rulesMatcher = rulesMatcher;
|
|
861
941
|
exports.rulesMatcherUtils = rulesMatcherUtils;
|
|
942
|
+
exports.setSubject = setSubject;
|
package/dist/index.esm.js
CHANGED
|
@@ -60,6 +60,89 @@ const generateData = (data) => {
|
|
|
60
60
|
};
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
class AbacEngine {
|
|
64
|
+
constructor(rules = []) {
|
|
65
|
+
// compile string conditions once
|
|
66
|
+
this.rules = (rules || [])
|
|
67
|
+
.map((r) => {
|
|
68
|
+
let conditionFn = undefined;
|
|
69
|
+
if (r.condition) {
|
|
70
|
+
try {
|
|
71
|
+
// NOTE: uses new Function -> ensure rules.json is trusted by the app owner
|
|
72
|
+
conditionFn = new Function('subject', 'resource', 'action', 'environment', `return (${r.condition});`);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error('ABAC: failed to compile rule condition', r.id, err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { ...r, conditionFn };
|
|
79
|
+
})
|
|
80
|
+
.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
81
|
+
}
|
|
82
|
+
decide(ctx) {
|
|
83
|
+
let anyPermit = false;
|
|
84
|
+
for (const r of this.rules) {
|
|
85
|
+
const matchesAction = Array.isArray(r.action)
|
|
86
|
+
? r.action.includes(ctx.action)
|
|
87
|
+
: r.action === ctx.action || r.action === '*';
|
|
88
|
+
if (!matchesAction)
|
|
89
|
+
continue;
|
|
90
|
+
let matches = true;
|
|
91
|
+
if (r.conditionFn) {
|
|
92
|
+
try {
|
|
93
|
+
matches = !!r.conditionFn(ctx.subject, ctx.resource, ctx.action, ctx.environment);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
matches = false;
|
|
97
|
+
console.error(`ABAC: rule ${r.id} threw while evaluating`, err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!matches)
|
|
101
|
+
continue;
|
|
102
|
+
if (r.effect === 'Deny') {
|
|
103
|
+
// deny-overrides
|
|
104
|
+
return 'Deny';
|
|
105
|
+
}
|
|
106
|
+
if (r.effect === 'Permit') {
|
|
107
|
+
anyPermit = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return anyPermit ? 'Permit' : 'Deny';
|
|
111
|
+
}
|
|
112
|
+
// utility: checks multiple actions and returns those allowed
|
|
113
|
+
allowedActions(ctxBase, actions) {
|
|
114
|
+
return actions.filter((a) => this.decide({ ...ctxBase, action: a }) === 'Permit');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let engine = null;
|
|
119
|
+
let rawRules = null;
|
|
120
|
+
let currentSubject = null;
|
|
121
|
+
function initAbac(rules) {
|
|
122
|
+
engine = new AbacEngine(rules);
|
|
123
|
+
rawRules = rules;
|
|
124
|
+
}
|
|
125
|
+
function getAbacEngine() {
|
|
126
|
+
if (!engine)
|
|
127
|
+
console.warn('ABAC engine non inizializzato');
|
|
128
|
+
return engine;
|
|
129
|
+
}
|
|
130
|
+
function getRawRules() {
|
|
131
|
+
return rawRules;
|
|
132
|
+
}
|
|
133
|
+
function isAbacInitialized() {
|
|
134
|
+
return engine !== null;
|
|
135
|
+
}
|
|
136
|
+
function setSubject(subject) {
|
|
137
|
+
currentSubject = subject;
|
|
138
|
+
}
|
|
139
|
+
function getSubject() {
|
|
140
|
+
return currentSubject;
|
|
141
|
+
}
|
|
142
|
+
function clearSubject() {
|
|
143
|
+
currentSubject = null;
|
|
144
|
+
}
|
|
145
|
+
|
|
63
146
|
const EMPTY_STRING_REGEXP = /^\s*$/;
|
|
64
147
|
/**
|
|
65
148
|
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
|
@@ -83,6 +166,11 @@ const rulesMatcherUtils = {
|
|
|
83
166
|
if (!operators[op]) {
|
|
84
167
|
throw new Error(`Error missing operator:${op}`);
|
|
85
168
|
}
|
|
169
|
+
if (op === '$can') {
|
|
170
|
+
const subject = getSubject();
|
|
171
|
+
const valid = operators['$can'](subject ?? {}, _get(value, 'action'), _get(value, 'resource'));
|
|
172
|
+
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
173
|
+
}
|
|
86
174
|
const valid = operators[op] && operators[op](valueForKey, valueRef, opt, data);
|
|
87
175
|
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
88
176
|
},
|
|
@@ -240,6 +328,11 @@ const rulesMatcherUtils = {
|
|
|
240
328
|
* Defines a set of comparison operators used for matching rules against user input.
|
|
241
329
|
*/
|
|
242
330
|
const operators = {
|
|
331
|
+
$can: (subject, action, resource) => getAbacEngine()?.decide({
|
|
332
|
+
subject: subject ?? {},
|
|
333
|
+
action,
|
|
334
|
+
resource
|
|
335
|
+
}) === 'Permit',
|
|
243
336
|
$exists: (a, b) => !rulesMatcherUtils.isEmpty(a) === b,
|
|
244
337
|
$eq: (a, b) => a === b,
|
|
245
338
|
$ne: (a, b) => a !== b,
|
|
@@ -302,9 +395,6 @@ const flattenRules = (ob) => {
|
|
|
302
395
|
}
|
|
303
396
|
return result;
|
|
304
397
|
};
|
|
305
|
-
const getRulesExists = (rules) => {
|
|
306
|
-
return Object.keys(rules).length ? FlowUtils.mapEdge(rules) : undefined;
|
|
307
|
-
};
|
|
308
398
|
const FlowUtils = {
|
|
309
399
|
generateRulesName: (nextRules) => {
|
|
310
400
|
return nextRules.reduce((acc, inc) => {
|
|
@@ -361,23 +451,6 @@ const FlowUtils = {
|
|
|
361
451
|
return res;
|
|
362
452
|
},
|
|
363
453
|
makeRules: (rules) => Object.entries(rules).reduce((acc2, [k, v]) => [...acc2, { nodeId: k, rules: v }], []),
|
|
364
|
-
// TODO: This function is strictly related to React nodes, could make sense to move it in the flower-react folder
|
|
365
|
-
generateNodesForFlowerJson: (nodes) => nodes
|
|
366
|
-
.filter((e) => !!_get(e, 'props.id'))
|
|
367
|
-
.map((e) => {
|
|
368
|
-
const rules = FlowUtils.makeRules(e.props.to ?? {});
|
|
369
|
-
const nextRules = getRulesExists(rules);
|
|
370
|
-
const children = e.props.data?.children;
|
|
371
|
-
return {
|
|
372
|
-
nodeId: e.props.id,
|
|
373
|
-
nodeType: e.type.displayName || e.props.as || 'FlowerNode',
|
|
374
|
-
nodeTitle: _get(e.props, 'data.title'),
|
|
375
|
-
children,
|
|
376
|
-
nextRules,
|
|
377
|
-
retain: e.props.retain,
|
|
378
|
-
disabled: e.props.disabled
|
|
379
|
-
};
|
|
380
|
-
}),
|
|
381
454
|
allEqual: (arr, arr2) => arr.length === arr2.length && arr.every((v) => arr2.includes(v)),
|
|
382
455
|
findValidRule: (nextRules, value, prefix) => find(nextRules, (rule) => {
|
|
383
456
|
// fix per evitare di entrare in un nodo senza regole, ma con un name,
|
|
@@ -648,7 +721,7 @@ const FlowerCoreBaseReducers = {
|
|
|
648
721
|
payload: { name: flowName, node: nextNumberNode }
|
|
649
722
|
});
|
|
650
723
|
},
|
|
651
|
-
|
|
724
|
+
back: (state, { payload }) => {
|
|
652
725
|
const { name, flowName } = payload;
|
|
653
726
|
FlowerCoreBaseReducers.historyPop(state, {
|
|
654
727
|
type: 'historyPop',
|
|
@@ -841,4 +914,4 @@ const FlowerCoreStateSelectors = {
|
|
|
841
914
|
...FlowerCoreStateDataSelectors
|
|
842
915
|
};
|
|
843
916
|
|
|
844
|
-
export { CoreUtils, DataUtils, Emitter, FlowUtils, FlowerCoreBaseReducers, FlowerCoreDataReducers, FlowerCoreReducers, FlowerCoreStateBaseSelectors, FlowerCoreStateDataSelectors, FlowerCoreStateSelectors, FlowerStateUtils, REDUCER_NAME, devtoolState, flattenRules, generateData, rulesMatcher, rulesMatcherUtils };
|
|
917
|
+
export { AbacEngine, CoreUtils, DataUtils, Emitter, FlowUtils, FlowerCoreBaseReducers, FlowerCoreDataReducers, FlowerCoreReducers, FlowerCoreStateBaseSelectors, FlowerCoreStateDataSelectors, FlowerCoreStateSelectors, FlowerStateUtils, REDUCER_NAME, clearSubject, devtoolState, flattenRules, generateData, getAbacEngine, getRawRules, getSubject, initAbac, isAbacInitialized, rulesMatcher, rulesMatcherUtils, setSubject };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type Action = string;
|
|
2
|
+
export type Subject = Record<string, any>;
|
|
3
|
+
export type Resource = Record<string, any>;
|
|
4
|
+
export type Environment = Record<string, any>;
|
|
5
|
+
export type AbacCtx = {
|
|
6
|
+
subject: Subject;
|
|
7
|
+
resource?: Resource;
|
|
8
|
+
action: Action;
|
|
9
|
+
environment?: Environment;
|
|
10
|
+
};
|
|
11
|
+
export type RuleInput = {
|
|
12
|
+
id: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
effect: 'Permit' | 'Deny';
|
|
15
|
+
priority?: number;
|
|
16
|
+
action?: string | string[];
|
|
17
|
+
/**
|
|
18
|
+
* condition: string JS expression that returns boolean.
|
|
19
|
+
* It can reference `subject`, `resource`, `action`, `environment`.
|
|
20
|
+
* Example: "action === 'read' && (!resource.confidential || resource.ownerID === subject.id)"
|
|
21
|
+
*/
|
|
22
|
+
condition?: string;
|
|
23
|
+
};
|
|
24
|
+
export type CompiledRule = RuleInput & {
|
|
25
|
+
conditionFn?: (subject: Subject, resource?: Resource, action?: Action, environment?: Environment) => boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare class AbacEngine {
|
|
28
|
+
private rules;
|
|
29
|
+
constructor(rules?: RuleInput[]);
|
|
30
|
+
decide(ctx: AbacCtx): 'Permit' | 'Deny';
|
|
31
|
+
allowedActions(ctxBase: Omit<AbacCtx, 'action'>, actions: Action[]): string[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AbacEngine, RuleInput, Subject } from './abacEngine';
|
|
2
|
+
export declare function initAbac(rules: RuleInput[]): void;
|
|
3
|
+
export declare function getAbacEngine(): AbacEngine | null;
|
|
4
|
+
export declare function getRawRules(): RuleInput[] | null;
|
|
5
|
+
export declare function isAbacInitialized(): boolean;
|
|
6
|
+
export declare function setSubject(subject: Subject): void;
|
|
7
|
+
export declare function getSubject(): Subject | null;
|
|
8
|
+
export declare function clearSubject(): void;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare enum RulesOperators {
|
|
2
2
|
$exists = "$exists",
|
|
3
|
+
$can = "$can",
|
|
3
4
|
$eq = "$eq",
|
|
4
5
|
$ne = "$ne",
|
|
5
6
|
$gt = "$gt",
|
|
@@ -26,6 +27,15 @@ export type Edge<T = object> = {
|
|
|
26
27
|
rules: RulesObject<T>;
|
|
27
28
|
};
|
|
28
29
|
};
|
|
30
|
+
export type NodeConfig = {
|
|
31
|
+
nodeId: string | undefined;
|
|
32
|
+
nodeType: string;
|
|
33
|
+
nodeTitle: string;
|
|
34
|
+
children: Node['children'];
|
|
35
|
+
nextRules: ReturnType<MapEdge> | undefined;
|
|
36
|
+
retain: boolean;
|
|
37
|
+
disabled: boolean;
|
|
38
|
+
};
|
|
29
39
|
export type Node = {
|
|
30
40
|
nodeId: string | undefined;
|
|
31
41
|
nodeType: string;
|
|
@@ -93,22 +103,12 @@ export type MapEdge<K = RulesByNodeId<any>, T = K[]> = (nextNode: T) => Array<K>
|
|
|
93
103
|
export type MakeRules<T extends Record<string, any> = {
|
|
94
104
|
rules: RulesObject<any> | object;
|
|
95
105
|
}> = (rules: T) => Array<RulesByNodeId<T>>;
|
|
96
|
-
export type GetRulesExists = (rules: RulesByNodeId<any>[]) => ReturnType<MapEdge> | undefined;
|
|
97
|
-
export type GenerateNodesForFlowerJson = (nodes: Node[], edges?: Edge[]) => {
|
|
98
|
-
nodeId: string | undefined;
|
|
99
|
-
nodeType: string;
|
|
100
|
-
nodeTitle: string;
|
|
101
|
-
children: Node['children'];
|
|
102
|
-
nextRules: ReturnType<GetRulesExists>;
|
|
103
|
-
retain: boolean;
|
|
104
|
-
disabled: boolean;
|
|
105
|
-
}[];
|
|
106
106
|
export type HasNode = (state: Record<string, any>, name: string, node: string) => boolean;
|
|
107
|
-
export type MakeObjectRules = (nodes:
|
|
107
|
+
export type MakeObjectRules = (nodes: NodeConfig[]) => {
|
|
108
108
|
[x: string]: Node['nextRules'];
|
|
109
109
|
};
|
|
110
|
-
export type GenerateNodes = (nodes:
|
|
111
|
-
[x: string]:
|
|
110
|
+
export type GenerateNodes = (nodes: NodeConfig[]) => {
|
|
111
|
+
[x: string]: Partial<Node>;
|
|
112
112
|
};
|
|
113
113
|
export type MapKeysDeepLodash = (obj: Record<string, any>, cb: (...args: any) => any, isRecursive?: boolean) => Record<string, any>;
|
|
114
114
|
export type GenerateRulesName = (nextRules: RulesWithName[]) => {
|
|
@@ -176,13 +176,6 @@ export interface FlowUtilitiesFunctions {
|
|
|
176
176
|
* @returns
|
|
177
177
|
*/
|
|
178
178
|
makeRules: MakeRules;
|
|
179
|
-
/**
|
|
180
|
-
* Generates nodes for a flower JSON structure, extracting rules and other properties.
|
|
181
|
-
* @param nodes
|
|
182
|
-
*
|
|
183
|
-
* @returns
|
|
184
|
-
*/
|
|
185
|
-
generateNodesForFlowerJson: GenerateNodesForFlowerJson;
|
|
186
179
|
/**
|
|
187
180
|
* Checks if two arrays are equal in length and have the same elements.
|
|
188
181
|
* @param arr
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NodeConfig } from './CoreInterface';
|
|
2
2
|
import { Flower } from './Store';
|
|
3
3
|
export type ActionWithPayload<T> = {
|
|
4
4
|
type: string;
|
|
5
5
|
payload: T;
|
|
6
6
|
};
|
|
7
7
|
type ReducerFunctionSign<T extends object, R> = (state: Record<string, Flower<T>>, action: ActionWithPayload<R>) => Record<string, Flower<T>> | void;
|
|
8
|
-
export type CoreReducersFunctions<T extends Record<string, any> = Record<
|
|
8
|
+
export type CoreReducersFunctions<T extends Record<string, any> = Record<FlowCaseReducersNames, Flower<Record<string, any>>>> = {
|
|
9
9
|
/**
|
|
10
10
|
* @param state
|
|
11
11
|
* @param action
|
|
@@ -126,7 +126,7 @@ export type CoreReducersFunctions<T extends Record<string, any> = Record<string,
|
|
|
126
126
|
name: string;
|
|
127
127
|
startId: string;
|
|
128
128
|
persist: boolean;
|
|
129
|
-
nodes:
|
|
129
|
+
nodes: NodeConfig[];
|
|
130
130
|
initialState: {
|
|
131
131
|
startId?: string;
|
|
132
132
|
current?: string;
|
|
@@ -197,7 +197,7 @@ export type CoreReducersFunctions<T extends Record<string, any> = Record<string,
|
|
|
197
197
|
*
|
|
198
198
|
* @returns state
|
|
199
199
|
*/
|
|
200
|
-
|
|
200
|
+
back: ReducerFunctionSign<T, {
|
|
201
201
|
name?: string;
|
|
202
202
|
flowName?: string;
|
|
203
203
|
}>;
|
|
@@ -235,10 +235,11 @@ export type CoreReducersFunctions<T extends Record<string, any> = Record<string,
|
|
|
235
235
|
*/
|
|
236
236
|
>;
|
|
237
237
|
};
|
|
238
|
+
export type FlowCaseReducersNames = 'historyAdd' | 'historyPrevToNode' | 'forceAddHistory' | 'historyPop' | 'restoreHistory' | 'replaceNode' | 'forceResetHistory' | 'destroy' | 'initNodes' | 'setCurrentNode' | 'node' | 'prevToNode' | 'next' | 'back' | 'restart' | 'reset';
|
|
238
239
|
type DataReducerFunctionSign<T extends object, R = object> = (state: Record<string, T>, action: ActionWithPayload<{
|
|
239
240
|
rootName: string;
|
|
240
241
|
} & R>) => Record<string, T> | void;
|
|
241
|
-
export type DataReducersFunctions<T extends Record<string, any> = Record<
|
|
242
|
+
export type DataReducersFunctions<T extends Record<string, any> = Record<DataCaseReducersNames, Record<string, any>>> = {
|
|
242
243
|
/**
|
|
243
244
|
* @param state
|
|
244
245
|
* @param action
|
|
@@ -403,4 +404,5 @@ export type DataReducersFunctions<T extends Record<string, any> = Record<string,
|
|
|
403
404
|
initialData: Record<string, any>;
|
|
404
405
|
}>;
|
|
405
406
|
};
|
|
407
|
+
export type DataCaseReducersNames = 'setFormSubmitted' | 'addCustomDataErrors' | 'addDataErrors' | 'fieldDirty' | 'fieldTouch' | 'fieldFocus' | 'removeDataErrors' | 'addData' | 'addDataByPath' | 'replaceData' | 'unsetData' | 'setIsDataValidating' | 'resetData' | 'initData';
|
|
406
408
|
export {};
|
|
@@ -161,7 +161,18 @@ export interface RulesMatcherUtils {
|
|
|
161
161
|
getKeys: <T extends Record<string, any>>(rules?: T, options?: Record<string, any>) => string[] | null;
|
|
162
162
|
}
|
|
163
163
|
export type OperatorsFunction = (a: any, b: any, opt?: any, data?: any) => boolean;
|
|
164
|
+
export type DecisionFunction = (subject: Record<string, any>, action: string, resource: Record<string, any>) => boolean;
|
|
164
165
|
export type Operators = {
|
|
166
|
+
/**
|
|
167
|
+
* @param subject
|
|
168
|
+
* @param action
|
|
169
|
+
* @param resource
|
|
170
|
+
*
|
|
171
|
+
* Checks if a operation is denied or permitted based on ABAC rules.
|
|
172
|
+
*
|
|
173
|
+
* @returns
|
|
174
|
+
*/
|
|
175
|
+
$can: DecisionFunction;
|
|
165
176
|
/**
|
|
166
177
|
* @param a
|
|
167
178
|
* @param b
|