@memberjunction/global 2.74.0 → 2.76.0
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/dist/SafeExpressionEvaluator.d.ts +141 -0
- package/dist/SafeExpressionEvaluator.d.ts.map +1 -0
- package/dist/SafeExpressionEvaluator.js +316 -0
- package/dist/SafeExpressionEvaluator.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +159 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Safe expression evaluator for conditional logic in MemberJunction.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a secure way to evaluate boolean expressions against
|
|
5
|
+
* context objects without allowing arbitrary code execution. It supports
|
|
6
|
+
* dot notation for nested property access and common comparison operations.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/global
|
|
9
|
+
* @author MemberJunction.com
|
|
10
|
+
* @since 2.76.0
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Result of expression evaluation including success status and diagnostics
|
|
14
|
+
*/
|
|
15
|
+
export interface ExpressionEvaluationResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
value?: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
diagnostics?: {
|
|
20
|
+
expression: string;
|
|
21
|
+
context: Record<string, any>;
|
|
22
|
+
evaluationTime: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Safe expression evaluator that prevents arbitrary code execution while
|
|
27
|
+
* supporting common boolean expressions and property access patterns.
|
|
28
|
+
*
|
|
29
|
+
* Supported operations:
|
|
30
|
+
* - Comparison: ==, ===, !=, !==, <, >, <=, >=
|
|
31
|
+
* - Logical: &&, ||, !
|
|
32
|
+
* - Property access: dot notation (e.g., payload.customer.name)
|
|
33
|
+
* - Array access: bracket notation (e.g., items[0])
|
|
34
|
+
* - Safe methods: .length, .includes(), .startsWith(), .endsWith()
|
|
35
|
+
* - Array methods: .some(), .every(), .find(), .filter()
|
|
36
|
+
* - Type checking: typeof, instanceof (limited to safe types)
|
|
37
|
+
*
|
|
38
|
+
* @class SafeExpressionEvaluator
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const evaluator = new SafeExpressionEvaluator();
|
|
43
|
+
*
|
|
44
|
+
* // Simple comparison
|
|
45
|
+
* const result1 = evaluator.evaluate(
|
|
46
|
+
* "status == 'active'",
|
|
47
|
+
* { status: 'active' }
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* // Nested property access
|
|
51
|
+
* const result2 = evaluator.evaluate(
|
|
52
|
+
* "payload.customer.tier == 'premium' && payload.order.total > 1000",
|
|
53
|
+
* { payload: { customer: { tier: 'premium' }, order: { total: 1500 } } }
|
|
54
|
+
* );
|
|
55
|
+
*
|
|
56
|
+
* // Array methods
|
|
57
|
+
* const result3 = evaluator.evaluate(
|
|
58
|
+
* "items.some(item => item.price > 100)",
|
|
59
|
+
* { items: [{ price: 50 }, { price: 150 }] }
|
|
60
|
+
* );
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare class SafeExpressionEvaluator {
|
|
64
|
+
/**
|
|
65
|
+
* Patterns that indicate potentially dangerous code
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
private static readonly DANGEROUS_PATTERNS;
|
|
69
|
+
/**
|
|
70
|
+
* Safe methods that can be called on objects
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
private static readonly SAFE_METHODS;
|
|
74
|
+
/**
|
|
75
|
+
* Evaluates a boolean expression against a context object
|
|
76
|
+
*
|
|
77
|
+
* @param {string} expression - The boolean expression to evaluate
|
|
78
|
+
* @param {Record<string, any>} context - The context object containing variables
|
|
79
|
+
* @param {boolean} [enableDiagnostics=false] - Whether to include diagnostic information
|
|
80
|
+
*
|
|
81
|
+
* @returns {ExpressionEvaluationResult} The evaluation result
|
|
82
|
+
*/
|
|
83
|
+
evaluate(expression: string, context: Record<string, any>, enableDiagnostics?: boolean): ExpressionEvaluationResult;
|
|
84
|
+
/**
|
|
85
|
+
* Validates an expression for safety
|
|
86
|
+
*
|
|
87
|
+
* @param {string} expression - The expression to validate
|
|
88
|
+
*
|
|
89
|
+
* @returns {string | null} Error message if invalid, null if valid
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private validateExpression;
|
|
94
|
+
/**
|
|
95
|
+
* Creates a safe context object with only allowed properties
|
|
96
|
+
*
|
|
97
|
+
* @param {Record<string, any>} context - The original context
|
|
98
|
+
*
|
|
99
|
+
* @returns {Record<string, any>} The safe context
|
|
100
|
+
*
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
private createSafeContext;
|
|
104
|
+
/**
|
|
105
|
+
* Checks if a property name is potentially dangerous
|
|
106
|
+
*
|
|
107
|
+
* @param {string} name - The property name
|
|
108
|
+
*
|
|
109
|
+
* @returns {boolean} True if dangerous
|
|
110
|
+
*
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
private isDangerousPropertyName;
|
|
114
|
+
/**
|
|
115
|
+
* Safely clones a value for use in evaluation context
|
|
116
|
+
*
|
|
117
|
+
* @param {any} value - The value to clone
|
|
118
|
+
*
|
|
119
|
+
* @returns {any} The cloned value
|
|
120
|
+
*
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
private cloneValue;
|
|
124
|
+
/**
|
|
125
|
+
* Evaluates multiple expressions and returns all results
|
|
126
|
+
*
|
|
127
|
+
* @param {Array<{expression: string, name?: string}>} expressions - Array of expressions to evaluate
|
|
128
|
+
* @param {Record<string, any>} context - The context object
|
|
129
|
+
*
|
|
130
|
+
* @returns {Record<string, ExpressionEvaluationResult>} Map of results by name or index
|
|
131
|
+
*/
|
|
132
|
+
evaluateMultiple(expressions: Array<{
|
|
133
|
+
expression: string;
|
|
134
|
+
name?: string;
|
|
135
|
+
}>, context: Record<string, any>): Record<string, ExpressionEvaluationResult>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Default instance for convenience
|
|
139
|
+
*/
|
|
140
|
+
export declare const defaultExpressionEvaluator: SafeExpressionEvaluator;
|
|
141
|
+
//# sourceMappingURL=SafeExpressionEvaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeExpressionEvaluator.d.ts","sourceRoot":"","sources":["../src/SafeExpressionEvaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,cAAc,EAAE,MAAM,CAAC;KAC1B,CAAC;CACL;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,uBAAuB;IAChC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CA4BxC;IAEF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAoBlC;IAEF;;;;;;;;OAQG;IACI,QAAQ,CACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,iBAAiB,GAAE,OAAe,GACnC,0BAA0B;IA8D7B;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAgC1B;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;;;;;;OAQG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAU;IAqClB;;;;;;;OAOG;IACI,gBAAgB,CACnB,WAAW,EAAE,KAAK,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,EACvD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC;CAUhD;AAED;;GAEG;AACH,eAAO,MAAM,0BAA0B,yBAAgC,CAAC"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Safe expression evaluator for conditional logic in MemberJunction.
|
|
4
|
+
*
|
|
5
|
+
* This module provides a secure way to evaluate boolean expressions against
|
|
6
|
+
* context objects without allowing arbitrary code execution. It supports
|
|
7
|
+
* dot notation for nested property access and common comparison operations.
|
|
8
|
+
*
|
|
9
|
+
* @module @memberjunction/global
|
|
10
|
+
* @author MemberJunction.com
|
|
11
|
+
* @since 2.76.0
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.defaultExpressionEvaluator = exports.SafeExpressionEvaluator = void 0;
|
|
15
|
+
/**
|
|
16
|
+
* Safe expression evaluator that prevents arbitrary code execution while
|
|
17
|
+
* supporting common boolean expressions and property access patterns.
|
|
18
|
+
*
|
|
19
|
+
* Supported operations:
|
|
20
|
+
* - Comparison: ==, ===, !=, !==, <, >, <=, >=
|
|
21
|
+
* - Logical: &&, ||, !
|
|
22
|
+
* - Property access: dot notation (e.g., payload.customer.name)
|
|
23
|
+
* - Array access: bracket notation (e.g., items[0])
|
|
24
|
+
* - Safe methods: .length, .includes(), .startsWith(), .endsWith()
|
|
25
|
+
* - Array methods: .some(), .every(), .find(), .filter()
|
|
26
|
+
* - Type checking: typeof, instanceof (limited to safe types)
|
|
27
|
+
*
|
|
28
|
+
* @class SafeExpressionEvaluator
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const evaluator = new SafeExpressionEvaluator();
|
|
33
|
+
*
|
|
34
|
+
* // Simple comparison
|
|
35
|
+
* const result1 = evaluator.evaluate(
|
|
36
|
+
* "status == 'active'",
|
|
37
|
+
* { status: 'active' }
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* // Nested property access
|
|
41
|
+
* const result2 = evaluator.evaluate(
|
|
42
|
+
* "payload.customer.tier == 'premium' && payload.order.total > 1000",
|
|
43
|
+
* { payload: { customer: { tier: 'premium' }, order: { total: 1500 } } }
|
|
44
|
+
* );
|
|
45
|
+
*
|
|
46
|
+
* // Array methods
|
|
47
|
+
* const result3 = evaluator.evaluate(
|
|
48
|
+
* "items.some(item => item.price > 100)",
|
|
49
|
+
* { items: [{ price: 50 }, { price: 150 }] }
|
|
50
|
+
* );
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
class SafeExpressionEvaluator {
|
|
54
|
+
/**
|
|
55
|
+
* Evaluates a boolean expression against a context object
|
|
56
|
+
*
|
|
57
|
+
* @param {string} expression - The boolean expression to evaluate
|
|
58
|
+
* @param {Record<string, any>} context - The context object containing variables
|
|
59
|
+
* @param {boolean} [enableDiagnostics=false] - Whether to include diagnostic information
|
|
60
|
+
*
|
|
61
|
+
* @returns {ExpressionEvaluationResult} The evaluation result
|
|
62
|
+
*/
|
|
63
|
+
evaluate(expression, context, enableDiagnostics = false) {
|
|
64
|
+
const startTime = Date.now();
|
|
65
|
+
try {
|
|
66
|
+
// Validate expression safety
|
|
67
|
+
const validationError = this.validateExpression(expression);
|
|
68
|
+
if (validationError) {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
error: validationError,
|
|
72
|
+
diagnostics: enableDiagnostics ? {
|
|
73
|
+
expression,
|
|
74
|
+
context,
|
|
75
|
+
evaluationTime: Date.now() - startTime
|
|
76
|
+
} : undefined
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Prepare safe context
|
|
80
|
+
const safeContext = this.createSafeContext(context);
|
|
81
|
+
// Create evaluation function
|
|
82
|
+
const contextKeys = Object.keys(safeContext);
|
|
83
|
+
const contextValues = contextKeys.map(key => safeContext[key]);
|
|
84
|
+
// Build function body with strict mode
|
|
85
|
+
const functionBody = `
|
|
86
|
+
"use strict";
|
|
87
|
+
try {
|
|
88
|
+
return Boolean(${expression});
|
|
89
|
+
} catch (e) {
|
|
90
|
+
throw new Error('Expression evaluation failed: ' + e.message);
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
// Create and execute function
|
|
94
|
+
const evaluator = new Function(...contextKeys, functionBody);
|
|
95
|
+
const result = evaluator(...contextValues);
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
value: Boolean(result),
|
|
99
|
+
diagnostics: enableDiagnostics ? {
|
|
100
|
+
expression,
|
|
101
|
+
context,
|
|
102
|
+
evaluationTime: Date.now() - startTime
|
|
103
|
+
} : undefined
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
success: false,
|
|
109
|
+
error: error instanceof Error ? error.message : String(error),
|
|
110
|
+
diagnostics: enableDiagnostics ? {
|
|
111
|
+
expression,
|
|
112
|
+
context,
|
|
113
|
+
evaluationTime: Date.now() - startTime
|
|
114
|
+
} : undefined
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Validates an expression for safety
|
|
120
|
+
*
|
|
121
|
+
* @param {string} expression - The expression to validate
|
|
122
|
+
*
|
|
123
|
+
* @returns {string | null} Error message if invalid, null if valid
|
|
124
|
+
*
|
|
125
|
+
* @private
|
|
126
|
+
*/
|
|
127
|
+
validateExpression(expression) {
|
|
128
|
+
if (!expression || typeof expression !== 'string') {
|
|
129
|
+
return 'Expression must be a non-empty string';
|
|
130
|
+
}
|
|
131
|
+
if (expression.length > 1000) {
|
|
132
|
+
return 'Expression exceeds maximum length of 1000 characters';
|
|
133
|
+
}
|
|
134
|
+
// Check for dangerous patterns
|
|
135
|
+
for (const pattern of SafeExpressionEvaluator.DANGEROUS_PATTERNS) {
|
|
136
|
+
if (pattern.test(expression)) {
|
|
137
|
+
return `Expression contains forbidden construct: ${pattern.source}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Basic syntax validation - ensure balanced parentheses
|
|
141
|
+
let parenCount = 0;
|
|
142
|
+
for (const char of expression) {
|
|
143
|
+
if (char === '(')
|
|
144
|
+
parenCount++;
|
|
145
|
+
if (char === ')')
|
|
146
|
+
parenCount--;
|
|
147
|
+
if (parenCount < 0) {
|
|
148
|
+
return 'Unbalanced parentheses in expression';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (parenCount !== 0) {
|
|
152
|
+
return 'Unbalanced parentheses in expression';
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Creates a safe context object with only allowed properties
|
|
158
|
+
*
|
|
159
|
+
* @param {Record<string, any>} context - The original context
|
|
160
|
+
*
|
|
161
|
+
* @returns {Record<string, any>} The safe context
|
|
162
|
+
*
|
|
163
|
+
* @private
|
|
164
|
+
*/
|
|
165
|
+
createSafeContext(context) {
|
|
166
|
+
// Deep clone to prevent modifications to original
|
|
167
|
+
const safeContext = {};
|
|
168
|
+
for (const [key, value] of Object.entries(context)) {
|
|
169
|
+
// Skip dangerous property names
|
|
170
|
+
if (this.isDangerousPropertyName(key)) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
// Clone value safely
|
|
174
|
+
safeContext[key] = this.cloneValue(value);
|
|
175
|
+
}
|
|
176
|
+
return safeContext;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Checks if a property name is potentially dangerous
|
|
180
|
+
*
|
|
181
|
+
* @param {string} name - The property name
|
|
182
|
+
*
|
|
183
|
+
* @returns {boolean} True if dangerous
|
|
184
|
+
*
|
|
185
|
+
* @private
|
|
186
|
+
*/
|
|
187
|
+
isDangerousPropertyName(name) {
|
|
188
|
+
const dangerous = [
|
|
189
|
+
'__proto__',
|
|
190
|
+
'constructor',
|
|
191
|
+
'prototype',
|
|
192
|
+
'eval',
|
|
193
|
+
'Function'
|
|
194
|
+
];
|
|
195
|
+
return dangerous.includes(name);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Safely clones a value for use in evaluation context
|
|
199
|
+
*
|
|
200
|
+
* @param {any} value - The value to clone
|
|
201
|
+
*
|
|
202
|
+
* @returns {any} The cloned value
|
|
203
|
+
*
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
cloneValue(value) {
|
|
207
|
+
if (value === null || value === undefined) {
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
const type = typeof value;
|
|
211
|
+
// Primitives are safe
|
|
212
|
+
if (type === 'string' || type === 'number' || type === 'boolean') {
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
// Arrays
|
|
216
|
+
if (Array.isArray(value)) {
|
|
217
|
+
return value.map(item => this.cloneValue(item));
|
|
218
|
+
}
|
|
219
|
+
// Plain objects
|
|
220
|
+
if (type === 'object' && value.constructor === Object) {
|
|
221
|
+
const cloned = {};
|
|
222
|
+
for (const [key, val] of Object.entries(value)) {
|
|
223
|
+
if (!this.isDangerousPropertyName(key)) {
|
|
224
|
+
cloned[key] = this.cloneValue(val);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return cloned;
|
|
228
|
+
}
|
|
229
|
+
// Dates
|
|
230
|
+
if (value instanceof Date) {
|
|
231
|
+
return new Date(value);
|
|
232
|
+
}
|
|
233
|
+
// For other types, return a safe representation
|
|
234
|
+
return String(value);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Evaluates multiple expressions and returns all results
|
|
238
|
+
*
|
|
239
|
+
* @param {Array<{expression: string, name?: string}>} expressions - Array of expressions to evaluate
|
|
240
|
+
* @param {Record<string, any>} context - The context object
|
|
241
|
+
*
|
|
242
|
+
* @returns {Record<string, ExpressionEvaluationResult>} Map of results by name or index
|
|
243
|
+
*/
|
|
244
|
+
evaluateMultiple(expressions, context) {
|
|
245
|
+
const results = {};
|
|
246
|
+
expressions.forEach((expr, index) => {
|
|
247
|
+
const key = expr.name || `expression_${index}`;
|
|
248
|
+
results[key] = this.evaluate(expr.expression, context);
|
|
249
|
+
});
|
|
250
|
+
return results;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.SafeExpressionEvaluator = SafeExpressionEvaluator;
|
|
254
|
+
/**
|
|
255
|
+
* Patterns that indicate potentially dangerous code
|
|
256
|
+
* @private
|
|
257
|
+
*/
|
|
258
|
+
SafeExpressionEvaluator.DANGEROUS_PATTERNS = [
|
|
259
|
+
/\beval\s*\(/i,
|
|
260
|
+
/\bnew\s+Function/i,
|
|
261
|
+
/\bFunction\s*\(/i,
|
|
262
|
+
/\bimport\s+/i,
|
|
263
|
+
/\brequire\s*\(/i,
|
|
264
|
+
/\bprocess\./i,
|
|
265
|
+
/\bglobal\./i,
|
|
266
|
+
/\bwindow\./i,
|
|
267
|
+
/\bdocument\./i,
|
|
268
|
+
/\b__proto__\b/i,
|
|
269
|
+
/\bconstructor\b/i,
|
|
270
|
+
/\bprototype\b/i,
|
|
271
|
+
/\.\s*constructor/i,
|
|
272
|
+
/\bthis\b/,
|
|
273
|
+
/\bawait\b/i,
|
|
274
|
+
/\basync\b/i,
|
|
275
|
+
/\bclass\b/i,
|
|
276
|
+
/\bextends\b/i,
|
|
277
|
+
/\bthrow\b/i,
|
|
278
|
+
/\btry\b/i,
|
|
279
|
+
/\bcatch\b/i,
|
|
280
|
+
/\bfinally\b/i,
|
|
281
|
+
/;/, // No semicolons to prevent multiple statements
|
|
282
|
+
/{/, // No curly braces to prevent code blocks
|
|
283
|
+
/}/, // No curly braces
|
|
284
|
+
/`/, // No template literals
|
|
285
|
+
/\$\{/, // No template expressions
|
|
286
|
+
];
|
|
287
|
+
/**
|
|
288
|
+
* Safe methods that can be called on objects
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
SafeExpressionEvaluator.SAFE_METHODS = [
|
|
292
|
+
'length',
|
|
293
|
+
'includes',
|
|
294
|
+
'startsWith',
|
|
295
|
+
'endsWith',
|
|
296
|
+
'indexOf',
|
|
297
|
+
'lastIndexOf',
|
|
298
|
+
'toLowerCase',
|
|
299
|
+
'toUpperCase',
|
|
300
|
+
'trim',
|
|
301
|
+
'trimStart',
|
|
302
|
+
'trimEnd',
|
|
303
|
+
'toString',
|
|
304
|
+
'valueOf',
|
|
305
|
+
'some',
|
|
306
|
+
'every',
|
|
307
|
+
'find',
|
|
308
|
+
'filter',
|
|
309
|
+
'map',
|
|
310
|
+
'reduce'
|
|
311
|
+
];
|
|
312
|
+
/**
|
|
313
|
+
* Default instance for convenience
|
|
314
|
+
*/
|
|
315
|
+
exports.defaultExpressionEvaluator = new SafeExpressionEvaluator();
|
|
316
|
+
//# sourceMappingURL=SafeExpressionEvaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeExpressionEvaluator.js","sourceRoot":"","sources":["../src/SafeExpressionEvaluator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './ClassUtils';
|
|
|
8
8
|
export * from './util/PatternUtils';
|
|
9
9
|
export * from './ValidationTypes';
|
|
10
10
|
export * from './JSONValidator';
|
|
11
|
+
export * from './SafeExpressionEvaluator';
|
|
11
12
|
export * from './Global';
|
|
12
13
|
export * from './RegisterClass';
|
|
13
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AAGzC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __exportStar(require("./ClassUtils"), exports);
|
|
|
28
28
|
__exportStar(require("./util/PatternUtils"), exports);
|
|
29
29
|
__exportStar(require("./ValidationTypes"), exports);
|
|
30
30
|
__exportStar(require("./JSONValidator"), exports);
|
|
31
|
+
__exportStar(require("./SafeExpressionEvaluator"), exports);
|
|
31
32
|
// Export the main classes
|
|
32
33
|
__exportStar(require("./Global"), exports);
|
|
33
34
|
__exportStar(require("./RegisterClass"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,iCAAiC;AACjC,+CAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,8CAA2B;AAC3B,yCAAsB;AACtB,gDAA6B;AAC7B,kDAA+B;AAC/B,6CAA0B;AAC1B,+CAA4B;AAC5B,sDAAoC;AACpC,oDAAiC;AACjC,kDAA+B;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,iCAAiC;AACjC,+CAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,8CAA2B;AAC3B,yCAAsB;AACtB,gDAA6B;AAC7B,kDAA+B;AAC/B,6CAA0B;AAC1B,+CAA4B;AAC5B,sDAAoC;AACpC,oDAAiC;AACjC,kDAA+B;AAC/B,4DAAyC;AAEzC,0BAA0B;AAC1B,2CAAwB;AACxB,kDAA+B"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -650,6 +650,165 @@ const html = ConvertMarkdownStringToHtmlList('Unordered', '- Item 1\n- Item 2\n-
|
|
|
650
650
|
// Returns: <ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
|
|
651
651
|
```
|
|
652
652
|
|
|
653
|
+
### Safe Expression Evaluator
|
|
654
|
+
|
|
655
|
+
Secure boolean expression evaluation for conditional logic without allowing arbitrary code execution:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
import { SafeExpressionEvaluator } from '@memberjunction/global';
|
|
659
|
+
|
|
660
|
+
// Create evaluator instance
|
|
661
|
+
const evaluator = new SafeExpressionEvaluator();
|
|
662
|
+
|
|
663
|
+
// Simple comparisons
|
|
664
|
+
const result1 = evaluator.evaluate(
|
|
665
|
+
"status == 'active' && score > 80",
|
|
666
|
+
{ status: 'active', score: 95 }
|
|
667
|
+
);
|
|
668
|
+
console.log(result1.success); // true
|
|
669
|
+
console.log(result1.value); // true
|
|
670
|
+
|
|
671
|
+
// Nested property access with dot notation
|
|
672
|
+
const result2 = evaluator.evaluate(
|
|
673
|
+
"user.role == 'admin' && user.permissions.includes('write')",
|
|
674
|
+
{
|
|
675
|
+
user: {
|
|
676
|
+
role: 'admin',
|
|
677
|
+
permissions: ['read', 'write', 'delete']
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
console.log(result2.value); // true
|
|
682
|
+
|
|
683
|
+
// Array methods and complex conditions
|
|
684
|
+
const result3 = evaluator.evaluate(
|
|
685
|
+
"items.some(item => item.price > 100) && items.length >= 2",
|
|
686
|
+
{
|
|
687
|
+
items: [
|
|
688
|
+
{ name: 'Item 1', price: 50 },
|
|
689
|
+
{ name: 'Item 2', price: 150 }
|
|
690
|
+
]
|
|
691
|
+
}
|
|
692
|
+
);
|
|
693
|
+
console.log(result3.value); // true
|
|
694
|
+
|
|
695
|
+
// Error handling for invalid expressions
|
|
696
|
+
const result4 = evaluator.evaluate(
|
|
697
|
+
"eval('malicious code')", // Dangerous patterns are blocked
|
|
698
|
+
{ data: 'test' }
|
|
699
|
+
);
|
|
700
|
+
console.log(result4.success); // false
|
|
701
|
+
console.log(result4.error); // "Expression contains forbidden construct: /\beval\s*\(/i"
|
|
702
|
+
|
|
703
|
+
// With diagnostics enabled
|
|
704
|
+
const result5 = evaluator.evaluate(
|
|
705
|
+
"payload.status == 'complete'",
|
|
706
|
+
{ payload: { status: 'complete' } },
|
|
707
|
+
true // Enable diagnostics
|
|
708
|
+
);
|
|
709
|
+
console.log(result5.diagnostics);
|
|
710
|
+
// {
|
|
711
|
+
// expression: "payload.status == 'complete'",
|
|
712
|
+
// context: { payload: { status: 'complete' } },
|
|
713
|
+
// evaluationTime: 2
|
|
714
|
+
// }
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
#### Supported Operations
|
|
718
|
+
|
|
719
|
+
**Comparison Operators:**
|
|
720
|
+
- `==`, `===`, `!=`, `!==`
|
|
721
|
+
- `<`, `>`, `<=`, `>=`
|
|
722
|
+
|
|
723
|
+
**Logical Operators:**
|
|
724
|
+
- `&&`, `||`, `!`
|
|
725
|
+
|
|
726
|
+
**Property Access:**
|
|
727
|
+
- Dot notation: `object.property.nested`
|
|
728
|
+
- Array access: `array[0]`, `array[index]`
|
|
729
|
+
|
|
730
|
+
**Safe Methods:**
|
|
731
|
+
- String: `.length`, `.includes()`, `.startsWith()`, `.endsWith()`, `.toLowerCase()`, `.toUpperCase()`, `.trim()`
|
|
732
|
+
- Array: `.length`, `.includes()`, `.some()`, `.every()`, `.find()`, `.filter()`, `.map()`
|
|
733
|
+
- Type checking: `typeof`, limited `instanceof`
|
|
734
|
+
|
|
735
|
+
**Type Coercion:**
|
|
736
|
+
- `Boolean(value)`
|
|
737
|
+
- String concatenation with `+`
|
|
738
|
+
|
|
739
|
+
#### Security Features
|
|
740
|
+
|
|
741
|
+
The evaluator blocks dangerous patterns including:
|
|
742
|
+
- `eval()`, `Function()`, `new Function()`
|
|
743
|
+
- `require()`, `import` statements
|
|
744
|
+
- Access to `global`, `window`, `document`, `process`
|
|
745
|
+
- Template literals and string interpolation
|
|
746
|
+
- Code blocks with `{}` and `;`
|
|
747
|
+
- `this` keyword usage
|
|
748
|
+
- `constructor`, `prototype`, `__proto__` access
|
|
749
|
+
|
|
750
|
+
#### Use Cases
|
|
751
|
+
|
|
752
|
+
1. **Workflow Conditions:**
|
|
753
|
+
```typescript
|
|
754
|
+
// Evaluate workflow paths
|
|
755
|
+
const canProceed = evaluator.evaluate(
|
|
756
|
+
"order.status == 'approved' && order.total < budget",
|
|
757
|
+
{ order: { status: 'approved', total: 500 }, budget: 1000 }
|
|
758
|
+
).value;
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
2. **Feature Flags:**
|
|
762
|
+
```typescript
|
|
763
|
+
// Check feature availability
|
|
764
|
+
const featureEnabled = evaluator.evaluate(
|
|
765
|
+
"user.tier == 'premium' || user.roles.includes('beta')",
|
|
766
|
+
{ user: { tier: 'standard', roles: ['beta', 'tester'] } }
|
|
767
|
+
).value;
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
3. **Validation Rules:**
|
|
771
|
+
```typescript
|
|
772
|
+
// Dynamic validation
|
|
773
|
+
const isValid = evaluator.evaluate(
|
|
774
|
+
"form.password.length >= 8 && form.password != form.username",
|
|
775
|
+
{ form: { username: 'john', password: 'secretpass123' } }
|
|
776
|
+
).value;
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
4. **Agent Decision Logic:**
|
|
780
|
+
```typescript
|
|
781
|
+
// AI agent path selection
|
|
782
|
+
const shouldDelegate = evaluator.evaluate(
|
|
783
|
+
"confidence < 0.7 || taskComplexity > 8",
|
|
784
|
+
{ confidence: 0.6, taskComplexity: 5 }
|
|
785
|
+
).value;
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
#### Batch Evaluation
|
|
789
|
+
|
|
790
|
+
Evaluate multiple expressions at once:
|
|
791
|
+
|
|
792
|
+
```typescript
|
|
793
|
+
const results = evaluator.evaluateMultiple([
|
|
794
|
+
{ expression: "status == 'active'", name: 'isActive' },
|
|
795
|
+
{ expression: "score > threshold", name: 'passedThreshold' },
|
|
796
|
+
{ expression: "tags.includes('priority')", name: 'isPriority' }
|
|
797
|
+
], {
|
|
798
|
+
status: 'active',
|
|
799
|
+
score: 85,
|
|
800
|
+
threshold: 80,
|
|
801
|
+
tags: ['urgent', 'priority']
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
// Results:
|
|
805
|
+
// {
|
|
806
|
+
// isActive: { success: true, value: true },
|
|
807
|
+
// passedThreshold: { success: true, value: true },
|
|
808
|
+
// isPriority: { success: true, value: true }
|
|
809
|
+
// }
|
|
810
|
+
```
|
|
811
|
+
|
|
653
812
|
### Pattern Matching Utilities
|
|
654
813
|
|
|
655
814
|
Convert string patterns to RegExp objects with support for simple wildcards and full regex syntax:
|