@nyariv/sandboxjs 0.8.22 → 0.8.24
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/.eslintignore +6 -0
- package/.eslintrc.js +22 -0
- package/.prettierrc +4 -0
- package/.vscode/settings.json +4 -0
- package/build/Sandbox.d.ts +11 -78
- package/build/Sandbox.js +21 -216
- package/build/SandboxExec.d.ts +25 -0
- package/build/SandboxExec.js +169 -0
- package/build/eval.d.ts +18 -0
- package/build/eval.js +43 -0
- package/build/executor.d.ts +56 -95
- package/build/executor.js +739 -815
- package/build/parser.d.ts +112 -74
- package/build/parser.js +504 -542
- package/build/unraw.js +13 -16
- package/build/utils.d.ts +242 -0
- package/build/utils.js +276 -0
- package/dist/Sandbox.d.ts +11 -78
- package/dist/Sandbox.js +106 -1
- package/dist/Sandbox.js.map +1 -1
- package/dist/Sandbox.min.js +1 -1
- package/dist/Sandbox.min.js.map +1 -1
- package/dist/SandboxExec.d.ts +25 -0
- package/dist/SandboxExec.js +173 -0
- package/dist/SandboxExec.js.map +1 -0
- package/dist/SandboxExec.min.js +2 -0
- package/dist/SandboxExec.min.js.map +1 -0
- package/dist/eval.d.ts +18 -0
- package/dist/executor.d.ts +56 -95
- package/dist/executor.js +1270 -0
- package/dist/executor.js.map +1 -0
- package/dist/node/Sandbox.d.ts +11 -78
- package/dist/node/Sandbox.js +37 -3091
- package/dist/node/SandboxExec.d.ts +25 -0
- package/dist/node/SandboxExec.js +176 -0
- package/dist/node/eval.d.ts +18 -0
- package/dist/node/executor.d.ts +56 -95
- package/dist/node/executor.js +1289 -0
- package/dist/node/parser.d.ts +112 -74
- package/dist/node/parser.js +1528 -0
- package/dist/node/utils.d.ts +242 -0
- package/dist/node/utils.js +290 -0
- package/dist/parser.d.ts +112 -74
- package/dist/parser.js +1514 -0
- package/dist/parser.js.map +1 -0
- package/dist/utils.d.ts +242 -0
- package/dist/utils.js +279 -0
- package/dist/utils.js.map +1 -0
- package/package.json +22 -14
- package/.github/workflows/npm-publish.yml +0 -34
package/.eslintignore
ADDED
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
browser: true,
|
|
4
|
+
es2021: true,
|
|
5
|
+
},
|
|
6
|
+
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
|
7
|
+
overrides: [],
|
|
8
|
+
parser: '@typescript-eslint/parser',
|
|
9
|
+
parserOptions: {
|
|
10
|
+
ecmaVersion: 'latest',
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
},
|
|
13
|
+
plugins: ['@typescript-eslint'],
|
|
14
|
+
rules: {
|
|
15
|
+
'no-prototype-builtins': 0,
|
|
16
|
+
'@typescript-eslint/no-explicit-any': 0,
|
|
17
|
+
'@typescript-eslint/ban-types': 0,
|
|
18
|
+
'@typescript-eslint/no-non-null-assertion': 0,
|
|
19
|
+
'no-cond-assign': 0,
|
|
20
|
+
'no-fallthrough': 0,
|
|
21
|
+
},
|
|
22
|
+
};
|
package/.prettierrc
ADDED
package/build/Sandbox.d.ts
CHANGED
|
@@ -1,90 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
prototypeWhitelist?: Map<any, Set<string>>;
|
|
10
|
-
globals: IGlobals;
|
|
11
|
-
executionQuota?: bigint;
|
|
12
|
-
onExecutionQuotaReached?: (ticks: Ticks, scope: Scope, context: IExecutionTree, tree: LispItem) => boolean | void;
|
|
13
|
-
}
|
|
14
|
-
export interface IContext {
|
|
15
|
-
sandbox: Sandbox;
|
|
16
|
-
globalScope: Scope;
|
|
17
|
-
sandboxGlobal: SandboxGlobal;
|
|
18
|
-
globalsWhitelist?: Set<any>;
|
|
19
|
-
prototypeWhitelist?: Map<any, Set<string>>;
|
|
20
|
-
options: IOptions;
|
|
21
|
-
auditReport?: IAuditReport;
|
|
22
|
-
}
|
|
23
|
-
export interface Ticks {
|
|
24
|
-
ticks: bigint;
|
|
25
|
-
}
|
|
26
|
-
export interface IExecContext extends IExecutionTree {
|
|
27
|
-
ctx: IContext;
|
|
28
|
-
getSubscriptions: Set<(obj: object, name: string) => void>;
|
|
29
|
-
setSubscriptions: WeakMap<object, Map<string, Set<(modification: Change) => void>>>;
|
|
30
|
-
changeSubscriptions: WeakMap<object, Set<(modification: Change) => void>>;
|
|
31
|
-
setSubscriptionsGlobal: WeakMap<object, Map<string, Set<(modification: Change) => void>>>;
|
|
32
|
-
changeSubscriptionsGlobal: WeakMap<object, Set<(modification: Change) => void>>;
|
|
33
|
-
registerSandboxFunction: (fn: (...args: any[]) => any) => void;
|
|
34
|
-
evals: Map<any, any>;
|
|
35
|
-
}
|
|
36
|
-
export declare class SandboxGlobal {
|
|
37
|
-
constructor(globals: IGlobals);
|
|
38
|
-
}
|
|
39
|
-
export declare class ExecContext implements IExecContext {
|
|
40
|
-
ctx: IContext;
|
|
41
|
-
constants: IConstants;
|
|
42
|
-
tree: LispArray;
|
|
43
|
-
getSubscriptions: Set<(obj: object, name: string) => void>;
|
|
44
|
-
setSubscriptions: WeakMap<object, Map<string, Set<(modification: Change) => void>>>;
|
|
45
|
-
changeSubscriptions: WeakMap<object, Set<(modification: Change) => void>>;
|
|
46
|
-
setSubscriptionsGlobal: WeakMap<object, Map<string, Set<(modification: Change) => void>>>;
|
|
47
|
-
changeSubscriptionsGlobal: WeakMap<object, Set<(modification: Change) => void>>;
|
|
48
|
-
evals: Map<any, any>;
|
|
49
|
-
registerSandboxFunction: (fn: (...args: any[]) => any) => void;
|
|
50
|
-
constructor(ctx: IContext, constants: IConstants, tree: LispArray, getSubscriptions: Set<(obj: object, name: string) => void>, setSubscriptions: WeakMap<object, Map<string, Set<(modification: Change) => void>>>, changeSubscriptions: WeakMap<object, Set<(modification: Change) => void>>, setSubscriptionsGlobal: WeakMap<object, Map<string, Set<(modification: Change) => void>>>, changeSubscriptionsGlobal: WeakMap<object, Set<(modification: Change) => void>>, evals: Map<any, any>, registerSandboxFunction: (fn: (...args: any[]) => any) => void);
|
|
51
|
-
}
|
|
52
|
-
export default class Sandbox {
|
|
53
|
-
context: IContext;
|
|
54
|
-
setSubscriptions: WeakMap<object, Map<string, Set<(modification: Change) => void>>>;
|
|
55
|
-
changeSubscriptions: WeakMap<object, Set<(modification: Change) => void>>;
|
|
56
|
-
sandboxFunctions: WeakMap<(...args: any[]) => any, IExecContext>;
|
|
57
|
-
constructor(options?: IOptions);
|
|
58
|
-
static get SAFE_GLOBALS(): IGlobals;
|
|
59
|
-
static get SAFE_PROTOTYPES(): Map<any, Set<string>>;
|
|
60
|
-
subscribeGet(callback: (obj: object, name: string) => void, context: IExecContext): {
|
|
61
|
-
unsubscribe: () => void;
|
|
62
|
-
};
|
|
63
|
-
subscribeSet(obj: object, name: string, callback: (modification: Change) => void, context: Sandbox | IExecContext): {
|
|
64
|
-
unsubscribe: () => void;
|
|
65
|
-
};
|
|
66
|
-
subscribeSetGlobal(obj: object, name: string, callback: (modification: Change) => void): {
|
|
67
|
-
unsubscribe: () => void;
|
|
68
|
-
};
|
|
69
|
-
static audit<T>(code: string, scopes?: (IScope)[]): ExecReturn<T>;
|
|
70
|
-
static parse(code: string): IExecutionTree;
|
|
71
|
-
createContext(context: IContext, executionTree: IExecutionTree): any;
|
|
72
|
-
getContext(fn: (...args: any[]) => any): IExecContext;
|
|
73
|
-
executeTree<T>(context: IExecContext, scopes?: (IScope)[]): ExecReturn<T>;
|
|
74
|
-
executeTreeAsync<T>(context: IExecContext, scopes?: (IScope)[]): Promise<ExecReturn<T>>;
|
|
75
|
-
compile<T>(code: string, optimize?: boolean): (...scopes: (IScope)[]) => {
|
|
1
|
+
import { IExecContext, IOptionParams, IScope } from './utils.js';
|
|
2
|
+
import { ExecReturn } from './executor.js';
|
|
3
|
+
import SandboxExec from './SandboxExec.js';
|
|
4
|
+
export default class Sandbox extends SandboxExec {
|
|
5
|
+
constructor(options?: IOptionParams);
|
|
6
|
+
static audit<T>(code: string, scopes?: IScope[]): ExecReturn<T>;
|
|
7
|
+
static parse(code: string): import("./parser.js").IExecutionTree;
|
|
8
|
+
compile<T>(code: string, optimize?: boolean): (...scopes: IScope[]) => {
|
|
76
9
|
context: IExecContext;
|
|
77
10
|
run: () => T;
|
|
78
11
|
};
|
|
79
|
-
compileAsync<T>(code: string, optimize?: boolean): (...scopes:
|
|
12
|
+
compileAsync<T>(code: string, optimize?: boolean): (...scopes: IScope[]) => {
|
|
80
13
|
context: IExecContext;
|
|
81
14
|
run: () => Promise<T>;
|
|
82
15
|
};
|
|
83
|
-
compileExpression<T>(code: string, optimize?: boolean): (...scopes:
|
|
16
|
+
compileExpression<T>(code: string, optimize?: boolean): (...scopes: IScope[]) => {
|
|
84
17
|
context: IExecContext;
|
|
85
18
|
run: () => T;
|
|
86
19
|
};
|
|
87
|
-
compileExpressionAsync<T>(code: string, optimize?: boolean): (...scopes:
|
|
20
|
+
compileExpressionAsync<T>(code: string, optimize?: boolean): (...scopes: IScope[]) => {
|
|
88
21
|
context: IExecContext;
|
|
89
22
|
run: () => Promise<T>;
|
|
90
23
|
};
|
package/build/Sandbox.js
CHANGED
|
@@ -1,246 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (globals === globalThis)
|
|
7
|
-
return globalThis;
|
|
8
|
-
for (let i in globals) {
|
|
9
|
-
this[i] = globals[i];
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export class ExecContext {
|
|
14
|
-
constructor(ctx, constants, tree, getSubscriptions, setSubscriptions, changeSubscriptions, setSubscriptionsGlobal, changeSubscriptionsGlobal, evals, registerSandboxFunction) {
|
|
15
|
-
this.ctx = ctx;
|
|
16
|
-
this.constants = constants;
|
|
17
|
-
this.tree = tree;
|
|
18
|
-
this.getSubscriptions = getSubscriptions;
|
|
19
|
-
this.setSubscriptions = setSubscriptions;
|
|
20
|
-
this.changeSubscriptions = changeSubscriptions;
|
|
21
|
-
this.setSubscriptionsGlobal = setSubscriptionsGlobal;
|
|
22
|
-
this.changeSubscriptionsGlobal = changeSubscriptionsGlobal;
|
|
23
|
-
this.evals = evals;
|
|
24
|
-
this.registerSandboxFunction = registerSandboxFunction;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function subscribeSet(obj, name, callback, context) {
|
|
28
|
-
const names = context.setSubscriptions.get(obj) || new Map();
|
|
29
|
-
context.setSubscriptions.set(obj, names);
|
|
30
|
-
const callbacks = names.get(name) || new Set();
|
|
31
|
-
names.set(name, callbacks);
|
|
32
|
-
callbacks.add(callback);
|
|
33
|
-
let changeCbs;
|
|
34
|
-
if (obj && obj[name] && typeof obj[name] === "object") {
|
|
35
|
-
changeCbs = context.changeSubscriptions.get(obj[name]) || new Set();
|
|
36
|
-
changeCbs.add(callback);
|
|
37
|
-
context.changeSubscriptions.set(obj[name], changeCbs);
|
|
38
|
-
}
|
|
39
|
-
return {
|
|
40
|
-
unsubscribe: () => {
|
|
41
|
-
callbacks.delete(callback);
|
|
42
|
-
changeCbs === null || changeCbs === void 0 ? void 0 : changeCbs.delete(callback);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
export default class Sandbox {
|
|
1
|
+
import { createExecContext } from './utils.js';
|
|
2
|
+
import { createEvalContext } from './eval.js';
|
|
3
|
+
import parse from './parser.js';
|
|
4
|
+
import SandboxExec from './SandboxExec.js';
|
|
5
|
+
export default class Sandbox extends SandboxExec {
|
|
47
6
|
constructor(options) {
|
|
48
|
-
|
|
49
|
-
this.changeSubscriptions = new WeakMap();
|
|
50
|
-
this.sandboxFunctions = new WeakMap();
|
|
51
|
-
options = Object.assign({
|
|
52
|
-
audit: false,
|
|
53
|
-
forbidFunctionCalls: false,
|
|
54
|
-
forbidFunctionCreation: false,
|
|
55
|
-
globals: Sandbox.SAFE_GLOBALS,
|
|
56
|
-
prototypeWhitelist: Sandbox.SAFE_PROTOTYPES,
|
|
57
|
-
prototypeReplacements: new Map(),
|
|
58
|
-
}, options || {});
|
|
59
|
-
const sandboxGlobal = new SandboxGlobal(options.globals);
|
|
60
|
-
this.context = {
|
|
61
|
-
sandbox: this,
|
|
62
|
-
globalsWhitelist: new Set(Object.values(options.globals)),
|
|
63
|
-
prototypeWhitelist: new Map([...options.prototypeWhitelist].map((a) => [a[0].prototype, a[1]])),
|
|
64
|
-
options,
|
|
65
|
-
globalScope: new Scope(null, options.globals, sandboxGlobal),
|
|
66
|
-
sandboxGlobal
|
|
67
|
-
};
|
|
68
|
-
this.context.prototypeWhitelist.set(Object.getPrototypeOf([][Symbol.iterator]()), new Set());
|
|
69
|
-
}
|
|
70
|
-
static get SAFE_GLOBALS() {
|
|
71
|
-
return {
|
|
72
|
-
Function,
|
|
73
|
-
console: {
|
|
74
|
-
debug: console.debug,
|
|
75
|
-
error: console.error,
|
|
76
|
-
info: console.info,
|
|
77
|
-
log: console.log,
|
|
78
|
-
table: console.table,
|
|
79
|
-
warn: console.warn
|
|
80
|
-
},
|
|
81
|
-
isFinite,
|
|
82
|
-
isNaN,
|
|
83
|
-
parseFloat,
|
|
84
|
-
parseInt,
|
|
85
|
-
decodeURI,
|
|
86
|
-
decodeURIComponent,
|
|
87
|
-
encodeURI,
|
|
88
|
-
encodeURIComponent,
|
|
89
|
-
escape,
|
|
90
|
-
unescape,
|
|
91
|
-
Boolean,
|
|
92
|
-
Number,
|
|
93
|
-
BigInt,
|
|
94
|
-
String,
|
|
95
|
-
Object,
|
|
96
|
-
Array,
|
|
97
|
-
Symbol,
|
|
98
|
-
Error,
|
|
99
|
-
EvalError,
|
|
100
|
-
RangeError,
|
|
101
|
-
ReferenceError,
|
|
102
|
-
SyntaxError,
|
|
103
|
-
TypeError,
|
|
104
|
-
URIError,
|
|
105
|
-
Int8Array,
|
|
106
|
-
Uint8Array,
|
|
107
|
-
Uint8ClampedArray,
|
|
108
|
-
Int16Array,
|
|
109
|
-
Uint16Array,
|
|
110
|
-
Int32Array,
|
|
111
|
-
Uint32Array,
|
|
112
|
-
Float32Array,
|
|
113
|
-
Float64Array,
|
|
114
|
-
Map,
|
|
115
|
-
Set,
|
|
116
|
-
WeakMap,
|
|
117
|
-
WeakSet,
|
|
118
|
-
Promise,
|
|
119
|
-
Intl,
|
|
120
|
-
JSON,
|
|
121
|
-
Math,
|
|
122
|
-
Date,
|
|
123
|
-
RegExp
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
static get SAFE_PROTOTYPES() {
|
|
127
|
-
let protos = [
|
|
128
|
-
SandboxGlobal,
|
|
129
|
-
Function,
|
|
130
|
-
Boolean,
|
|
131
|
-
Number,
|
|
132
|
-
BigInt,
|
|
133
|
-
String,
|
|
134
|
-
Date,
|
|
135
|
-
Error,
|
|
136
|
-
Array,
|
|
137
|
-
Int8Array,
|
|
138
|
-
Uint8Array,
|
|
139
|
-
Uint8ClampedArray,
|
|
140
|
-
Int16Array,
|
|
141
|
-
Uint16Array,
|
|
142
|
-
Int32Array,
|
|
143
|
-
Uint32Array,
|
|
144
|
-
Float32Array,
|
|
145
|
-
Float64Array,
|
|
146
|
-
Map,
|
|
147
|
-
Set,
|
|
148
|
-
WeakMap,
|
|
149
|
-
WeakSet,
|
|
150
|
-
Promise,
|
|
151
|
-
Symbol,
|
|
152
|
-
Date,
|
|
153
|
-
RegExp
|
|
154
|
-
];
|
|
155
|
-
let map = new Map();
|
|
156
|
-
protos.forEach((proto) => {
|
|
157
|
-
map.set(proto, new Set());
|
|
158
|
-
});
|
|
159
|
-
map.set(Object, new Set([
|
|
160
|
-
'entries',
|
|
161
|
-
'fromEntries',
|
|
162
|
-
'getOwnPropertyNames',
|
|
163
|
-
'is',
|
|
164
|
-
'keys',
|
|
165
|
-
'hasOwnProperty',
|
|
166
|
-
'isPrototypeOf',
|
|
167
|
-
'propertyIsEnumerable',
|
|
168
|
-
'toLocaleString',
|
|
169
|
-
'toString',
|
|
170
|
-
'valueOf',
|
|
171
|
-
'values'
|
|
172
|
-
]));
|
|
173
|
-
return map;
|
|
174
|
-
}
|
|
175
|
-
subscribeGet(callback, context) {
|
|
176
|
-
context.getSubscriptions.add(callback);
|
|
177
|
-
return { unsubscribe: () => context.getSubscriptions.delete(callback) };
|
|
178
|
-
}
|
|
179
|
-
subscribeSet(obj, name, callback, context) {
|
|
180
|
-
return subscribeSet(obj, name, callback, context);
|
|
181
|
-
}
|
|
182
|
-
subscribeSetGlobal(obj, name, callback) {
|
|
183
|
-
return subscribeSet(obj, name, callback, this);
|
|
7
|
+
super(options, createEvalContext());
|
|
184
8
|
}
|
|
185
9
|
static audit(code, scopes = []) {
|
|
186
10
|
const globals = {};
|
|
187
|
-
for (
|
|
11
|
+
for (const i of Object.getOwnPropertyNames(globalThis)) {
|
|
188
12
|
globals[i] = globalThis[i];
|
|
189
13
|
}
|
|
190
|
-
const sandbox = new
|
|
14
|
+
const sandbox = new SandboxExec({
|
|
191
15
|
globals,
|
|
192
16
|
audit: true,
|
|
193
17
|
});
|
|
194
|
-
return sandbox.executeTree(
|
|
18
|
+
return sandbox.executeTree(createExecContext(sandbox, parse(code, true), createEvalContext()), scopes);
|
|
195
19
|
}
|
|
196
20
|
static parse(code) {
|
|
197
21
|
return parse(code);
|
|
198
22
|
}
|
|
199
|
-
createContext(context, executionTree) {
|
|
200
|
-
const evals = new Map();
|
|
201
|
-
const execContext = new ExecContext(context, executionTree.constants, executionTree.tree, new Set(), new WeakMap(), new WeakMap(), this.setSubscriptions, this.changeSubscriptions, evals, (fn) => this.sandboxFunctions.set(fn, execContext));
|
|
202
|
-
const func = sandboxFunction(execContext);
|
|
203
|
-
evals.set(Function, func);
|
|
204
|
-
evals.set(eval, sandboxedEval(func));
|
|
205
|
-
evals.set(setTimeout, sandboxedSetTimeout(func));
|
|
206
|
-
evals.set(setInterval, sandboxedSetInterval(func));
|
|
207
|
-
return execContext;
|
|
208
|
-
}
|
|
209
|
-
getContext(fn) {
|
|
210
|
-
return this.sandboxFunctions.get(fn);
|
|
211
|
-
}
|
|
212
|
-
executeTree(context, scopes = []) {
|
|
213
|
-
return executeTree({
|
|
214
|
-
ticks: BigInt(0),
|
|
215
|
-
}, context, context.tree, scopes);
|
|
216
|
-
}
|
|
217
|
-
executeTreeAsync(context, scopes = []) {
|
|
218
|
-
return executeTreeAsync({
|
|
219
|
-
ticks: BigInt(0),
|
|
220
|
-
}, context, context.tree, scopes);
|
|
221
|
-
}
|
|
222
23
|
compile(code, optimize = false) {
|
|
223
24
|
const parsed = parse(code, optimize);
|
|
224
25
|
const exec = (...scopes) => {
|
|
225
|
-
const context =
|
|
26
|
+
const context = createExecContext(this, parsed, this.evalContext);
|
|
226
27
|
return { context, run: () => this.executeTree(context, [...scopes]).result };
|
|
227
28
|
};
|
|
228
29
|
return exec;
|
|
229
30
|
}
|
|
230
|
-
;
|
|
231
31
|
compileAsync(code, optimize = false) {
|
|
232
32
|
const parsed = parse(code, optimize);
|
|
233
33
|
const exec = (...scopes) => {
|
|
234
|
-
const context =
|
|
235
|
-
return {
|
|
34
|
+
const context = createExecContext(this, parsed, this.evalContext);
|
|
35
|
+
return {
|
|
36
|
+
context,
|
|
37
|
+
run: () => this.executeTreeAsync(context, [...scopes]).then((ret) => ret.result),
|
|
38
|
+
};
|
|
236
39
|
};
|
|
237
40
|
return exec;
|
|
238
41
|
}
|
|
239
|
-
;
|
|
240
42
|
compileExpression(code, optimize = false) {
|
|
241
43
|
const parsed = parse(code, optimize, true);
|
|
242
44
|
const exec = (...scopes) => {
|
|
243
|
-
const context =
|
|
45
|
+
const context = createExecContext(this, parsed, this.evalContext);
|
|
244
46
|
return { context, run: () => this.executeTree(context, [...scopes]).result };
|
|
245
47
|
};
|
|
246
48
|
return exec;
|
|
@@ -248,8 +50,11 @@ export default class Sandbox {
|
|
|
248
50
|
compileExpressionAsync(code, optimize = false) {
|
|
249
51
|
const parsed = parse(code, optimize, true);
|
|
250
52
|
const exec = (...scopes) => {
|
|
251
|
-
const context =
|
|
252
|
-
return {
|
|
53
|
+
const context = createExecContext(this, parsed, this.evalContext);
|
|
54
|
+
return {
|
|
55
|
+
context,
|
|
56
|
+
run: () => this.executeTreeAsync(context, [...scopes]).then((ret) => ret.result),
|
|
57
|
+
};
|
|
253
58
|
};
|
|
254
59
|
return exec;
|
|
255
60
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IEvalContext } from './eval.js';
|
|
2
|
+
import { Change, ExecReturn } from './executor.js';
|
|
3
|
+
import { IContext, IExecContext, IGlobals, IOptionParams, IScope, SubscriptionSubject } from './utils.js';
|
|
4
|
+
export default class SandboxExec {
|
|
5
|
+
evalContext?: IEvalContext | undefined;
|
|
6
|
+
context: IContext;
|
|
7
|
+
setSubscriptions: WeakMap<SubscriptionSubject, Map<string, Set<(modification: Change) => void>>>;
|
|
8
|
+
changeSubscriptions: WeakMap<SubscriptionSubject, Set<(modification: Change) => void>>;
|
|
9
|
+
sandboxFunctions: WeakMap<(...args: any[]) => any, IExecContext>;
|
|
10
|
+
constructor(options?: IOptionParams, evalContext?: IEvalContext | undefined);
|
|
11
|
+
static get SAFE_GLOBALS(): IGlobals;
|
|
12
|
+
static get SAFE_PROTOTYPES(): Map<any, Set<string>>;
|
|
13
|
+
subscribeGet(callback: (obj: SubscriptionSubject, name: string) => void, context: IExecContext): {
|
|
14
|
+
unsubscribe: () => void;
|
|
15
|
+
};
|
|
16
|
+
subscribeSet(obj: object, name: string, callback: (modification: Change) => void, context: SandboxExec | IExecContext): {
|
|
17
|
+
unsubscribe: () => void;
|
|
18
|
+
};
|
|
19
|
+
subscribeSetGlobal(obj: SubscriptionSubject, name: string, callback: (modification: Change) => void): {
|
|
20
|
+
unsubscribe: () => void;
|
|
21
|
+
};
|
|
22
|
+
getContext(fn: (...args: any[]) => any): IExecContext | undefined;
|
|
23
|
+
executeTree<T>(context: IExecContext, scopes?: IScope[]): ExecReturn<T>;
|
|
24
|
+
executeTreeAsync<T>(context: IExecContext, scopes?: IScope[]): Promise<ExecReturn<T>>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { executeTree, executeTreeAsync } from './executor.js';
|
|
2
|
+
import { createContext, SandboxGlobal, } from './utils.js';
|
|
3
|
+
function subscribeSet(obj, name, callback, context) {
|
|
4
|
+
if (!(obj instanceof Object))
|
|
5
|
+
throw new Error('Invalid subscription object, got ' + (typeof obj === 'object' ? 'null' : typeof obj));
|
|
6
|
+
const names = context.setSubscriptions.get(obj) || new Map();
|
|
7
|
+
context.setSubscriptions.set(obj, names);
|
|
8
|
+
const callbacks = names.get(name) || new Set();
|
|
9
|
+
names.set(name, callbacks);
|
|
10
|
+
callbacks.add(callback);
|
|
11
|
+
let changeCbs;
|
|
12
|
+
const val = obj[name];
|
|
13
|
+
if (val instanceof Object) {
|
|
14
|
+
changeCbs = context.changeSubscriptions.get(val) || new Set();
|
|
15
|
+
changeCbs.add(callback);
|
|
16
|
+
context.changeSubscriptions.set(val, changeCbs);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
unsubscribe: () => {
|
|
20
|
+
callbacks.delete(callback);
|
|
21
|
+
changeCbs?.delete(callback);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export default class SandboxExec {
|
|
26
|
+
constructor(options, evalContext) {
|
|
27
|
+
this.evalContext = evalContext;
|
|
28
|
+
this.setSubscriptions = new WeakMap();
|
|
29
|
+
this.changeSubscriptions = new WeakMap();
|
|
30
|
+
this.sandboxFunctions = new WeakMap();
|
|
31
|
+
const opt = Object.assign({
|
|
32
|
+
audit: false,
|
|
33
|
+
forbidFunctionCalls: false,
|
|
34
|
+
forbidFunctionCreation: false,
|
|
35
|
+
globals: SandboxExec.SAFE_GLOBALS,
|
|
36
|
+
prototypeWhitelist: SandboxExec.SAFE_PROTOTYPES,
|
|
37
|
+
prototypeReplacements: new Map(),
|
|
38
|
+
}, options || {});
|
|
39
|
+
this.context = createContext(this, opt);
|
|
40
|
+
}
|
|
41
|
+
static get SAFE_GLOBALS() {
|
|
42
|
+
return {
|
|
43
|
+
Function,
|
|
44
|
+
console: {
|
|
45
|
+
debug: console.debug,
|
|
46
|
+
error: console.error,
|
|
47
|
+
info: console.info,
|
|
48
|
+
log: console.log,
|
|
49
|
+
table: console.table,
|
|
50
|
+
warn: console.warn,
|
|
51
|
+
},
|
|
52
|
+
isFinite,
|
|
53
|
+
isNaN,
|
|
54
|
+
parseFloat,
|
|
55
|
+
parseInt,
|
|
56
|
+
decodeURI,
|
|
57
|
+
decodeURIComponent,
|
|
58
|
+
encodeURI,
|
|
59
|
+
encodeURIComponent,
|
|
60
|
+
escape,
|
|
61
|
+
unescape,
|
|
62
|
+
Boolean,
|
|
63
|
+
Number,
|
|
64
|
+
BigInt,
|
|
65
|
+
String,
|
|
66
|
+
Object,
|
|
67
|
+
Array,
|
|
68
|
+
Symbol,
|
|
69
|
+
Error,
|
|
70
|
+
EvalError,
|
|
71
|
+
RangeError,
|
|
72
|
+
ReferenceError,
|
|
73
|
+
SyntaxError,
|
|
74
|
+
TypeError,
|
|
75
|
+
URIError,
|
|
76
|
+
Int8Array,
|
|
77
|
+
Uint8Array,
|
|
78
|
+
Uint8ClampedArray,
|
|
79
|
+
Int16Array,
|
|
80
|
+
Uint16Array,
|
|
81
|
+
Int32Array,
|
|
82
|
+
Uint32Array,
|
|
83
|
+
Float32Array,
|
|
84
|
+
Float64Array,
|
|
85
|
+
Map,
|
|
86
|
+
Set,
|
|
87
|
+
WeakMap,
|
|
88
|
+
WeakSet,
|
|
89
|
+
Promise,
|
|
90
|
+
Intl,
|
|
91
|
+
JSON,
|
|
92
|
+
Math,
|
|
93
|
+
Date,
|
|
94
|
+
RegExp,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
static get SAFE_PROTOTYPES() {
|
|
98
|
+
const protos = [
|
|
99
|
+
SandboxGlobal,
|
|
100
|
+
Function,
|
|
101
|
+
Boolean,
|
|
102
|
+
Number,
|
|
103
|
+
BigInt,
|
|
104
|
+
String,
|
|
105
|
+
Date,
|
|
106
|
+
Error,
|
|
107
|
+
Array,
|
|
108
|
+
Int8Array,
|
|
109
|
+
Uint8Array,
|
|
110
|
+
Uint8ClampedArray,
|
|
111
|
+
Int16Array,
|
|
112
|
+
Uint16Array,
|
|
113
|
+
Int32Array,
|
|
114
|
+
Uint32Array,
|
|
115
|
+
Float32Array,
|
|
116
|
+
Float64Array,
|
|
117
|
+
Map,
|
|
118
|
+
Set,
|
|
119
|
+
WeakMap,
|
|
120
|
+
WeakSet,
|
|
121
|
+
Promise,
|
|
122
|
+
Symbol,
|
|
123
|
+
Date,
|
|
124
|
+
RegExp,
|
|
125
|
+
];
|
|
126
|
+
const map = new Map();
|
|
127
|
+
protos.forEach((proto) => {
|
|
128
|
+
map.set(proto, new Set());
|
|
129
|
+
});
|
|
130
|
+
map.set(Object, new Set([
|
|
131
|
+
'entries',
|
|
132
|
+
'fromEntries',
|
|
133
|
+
'getOwnPropertyNames',
|
|
134
|
+
'is',
|
|
135
|
+
'keys',
|
|
136
|
+
'hasOwnProperty',
|
|
137
|
+
'isPrototypeOf',
|
|
138
|
+
'propertyIsEnumerable',
|
|
139
|
+
'toLocaleString',
|
|
140
|
+
'toString',
|
|
141
|
+
'valueOf',
|
|
142
|
+
'values',
|
|
143
|
+
]));
|
|
144
|
+
return map;
|
|
145
|
+
}
|
|
146
|
+
subscribeGet(callback, context) {
|
|
147
|
+
context.getSubscriptions.add(callback);
|
|
148
|
+
return { unsubscribe: () => context.getSubscriptions.delete(callback) };
|
|
149
|
+
}
|
|
150
|
+
subscribeSet(obj, name, callback, context) {
|
|
151
|
+
return subscribeSet(obj, name, callback, context);
|
|
152
|
+
}
|
|
153
|
+
subscribeSetGlobal(obj, name, callback) {
|
|
154
|
+
return subscribeSet(obj, name, callback, this);
|
|
155
|
+
}
|
|
156
|
+
getContext(fn) {
|
|
157
|
+
return this.sandboxFunctions.get(fn);
|
|
158
|
+
}
|
|
159
|
+
executeTree(context, scopes = []) {
|
|
160
|
+
return executeTree({
|
|
161
|
+
ticks: BigInt(0),
|
|
162
|
+
}, context, context.tree, scopes);
|
|
163
|
+
}
|
|
164
|
+
executeTreeAsync(context, scopes = []) {
|
|
165
|
+
return executeTreeAsync({
|
|
166
|
+
ticks: BigInt(0),
|
|
167
|
+
}, context, context.tree, scopes);
|
|
168
|
+
}
|
|
169
|
+
}
|
package/build/eval.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { lispifyFunction } from './parser.js';
|
|
2
|
+
import { IExecContext, Ticks } from './utils.js';
|
|
3
|
+
export interface IEvalContext {
|
|
4
|
+
sandboxFunction: typeof sandboxFunction;
|
|
5
|
+
sandboxedEval: typeof sandboxedEval;
|
|
6
|
+
sandboxedSetTimeout: typeof sandboxedSetTimeout;
|
|
7
|
+
sandboxedSetInterval: typeof sandboxedSetInterval;
|
|
8
|
+
lispifyFunction: typeof lispifyFunction;
|
|
9
|
+
}
|
|
10
|
+
export type SandboxFunction = (code: string, ...args: string[]) => () => unknown;
|
|
11
|
+
export type SandboxEval = (code: string) => unknown;
|
|
12
|
+
export type SandboxSetTimeout = (handler: TimerHandler, timeout?: number, ...args: unknown[]) => any;
|
|
13
|
+
export type SandboxSetInterval = (handler: TimerHandler, timeout?: number, ...args: unknown[]) => any;
|
|
14
|
+
export declare function createEvalContext(): IEvalContext;
|
|
15
|
+
export declare function sandboxFunction(context: IExecContext, ticks?: Ticks): SandboxFunction;
|
|
16
|
+
export declare function sandboxedEval(func: SandboxFunction): SandboxEval;
|
|
17
|
+
export declare function sandboxedSetTimeout(func: SandboxFunction): SandboxSetTimeout;
|
|
18
|
+
export declare function sandboxedSetInterval(func: SandboxFunction): SandboxSetInterval;
|
package/build/eval.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createFunction, currentTicks } from './executor.js';
|
|
2
|
+
import parse, { lispifyFunction } from './parser.js';
|
|
3
|
+
export function createEvalContext() {
|
|
4
|
+
return {
|
|
5
|
+
sandboxFunction,
|
|
6
|
+
sandboxedEval,
|
|
7
|
+
sandboxedSetTimeout,
|
|
8
|
+
sandboxedSetInterval,
|
|
9
|
+
lispifyFunction,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function sandboxFunction(context, ticks) {
|
|
13
|
+
return SandboxFunction;
|
|
14
|
+
function SandboxFunction(...params) {
|
|
15
|
+
const code = params.pop() || '';
|
|
16
|
+
const parsed = parse(code);
|
|
17
|
+
return createFunction(params, parsed.tree, ticks || currentTicks.current, {
|
|
18
|
+
...context,
|
|
19
|
+
constants: parsed.constants,
|
|
20
|
+
tree: parsed.tree,
|
|
21
|
+
}, undefined, 'anonymous');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function sandboxedEval(func) {
|
|
25
|
+
return sandboxEval;
|
|
26
|
+
function sandboxEval(code) {
|
|
27
|
+
return func(code)();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function sandboxedSetTimeout(func) {
|
|
31
|
+
return function sandboxSetTimeout(handler, ...args) {
|
|
32
|
+
if (typeof handler !== 'string')
|
|
33
|
+
return setTimeout(handler, ...args);
|
|
34
|
+
return setTimeout(func(handler), ...args);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function sandboxedSetInterval(func) {
|
|
38
|
+
return function sandboxSetInterval(handler, ...args) {
|
|
39
|
+
if (typeof handler !== 'string')
|
|
40
|
+
return setInterval(handler, ...args);
|
|
41
|
+
return setInterval(func(handler), ...args);
|
|
42
|
+
};
|
|
43
|
+
}
|