@cuxt/sandboxjs 0.1.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/LICENSE +21 -0
- package/README.md +186 -0
- package/build/Sandbox.d.ts +25 -0
- package/build/Sandbox.js +62 -0
- package/build/SandboxExec.d.ts +66 -0
- package/build/SandboxExec.js +214 -0
- package/build/eval.d.ts +27 -0
- package/build/eval.js +205 -0
- package/build/executor.d.ts +124 -0
- package/build/executor.js +1546 -0
- package/build/parser.d.ts +154 -0
- package/build/parser.js +1527 -0
- package/build/unraw.d.ts +11 -0
- package/build/unraw.js +168 -0
- package/build/utils.d.ts +264 -0
- package/build/utils.js +362 -0
- package/dist/Sandbox.d.ts +25 -0
- package/dist/Sandbox.js +270 -0
- package/dist/Sandbox.js.map +1 -0
- package/dist/Sandbox.min.js +2 -0
- package/dist/Sandbox.min.js.map +1 -0
- package/dist/SandboxExec.d.ts +66 -0
- package/dist/SandboxExec.js +218 -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 +27 -0
- package/dist/executor.d.ts +124 -0
- package/dist/executor.js +1550 -0
- package/dist/executor.js.map +1 -0
- package/dist/node/Sandbox.d.ts +25 -0
- package/dist/node/Sandbox.js +277 -0
- package/dist/node/SandboxExec.d.ts +66 -0
- package/dist/node/SandboxExec.js +225 -0
- package/dist/node/eval.d.ts +27 -0
- package/dist/node/executor.d.ts +124 -0
- package/dist/node/executor.js +1567 -0
- package/dist/node/parser.d.ts +154 -0
- package/dist/node/parser.js +1704 -0
- package/dist/node/unraw.d.ts +11 -0
- package/dist/node/utils.d.ts +264 -0
- package/dist/node/utils.js +385 -0
- package/dist/parser.d.ts +154 -0
- package/dist/parser.js +1690 -0
- package/dist/parser.js.map +1 -0
- package/dist/unraw.d.ts +11 -0
- package/dist/utils.d.ts +264 -0
- package/dist/utils.js +365 -0
- package/dist/utils.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,1567 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('./utils.js');
|
|
4
|
+
|
|
5
|
+
class ExecReturn {
|
|
6
|
+
constructor(auditReport, result, returned, breakLoop = false, continueLoop = false) {
|
|
7
|
+
this.auditReport = auditReport;
|
|
8
|
+
this.result = result;
|
|
9
|
+
this.returned = returned;
|
|
10
|
+
this.breakLoop = breakLoop;
|
|
11
|
+
this.continueLoop = continueLoop;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const optional = {};
|
|
15
|
+
function generateArgs(argNames, args) {
|
|
16
|
+
const vars = {};
|
|
17
|
+
argNames.forEach((arg, i) => {
|
|
18
|
+
if (arg.startsWith('...')) {
|
|
19
|
+
vars[arg.substring(3)] = args.slice(i);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
vars[arg] = args[i];
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return vars;
|
|
26
|
+
}
|
|
27
|
+
function createFunction(argNames, parsed, ticks, context, scope, name) {
|
|
28
|
+
if (context.ctx.options.forbidFunctionCreation) {
|
|
29
|
+
throw new utils.SandboxCapabilityError('Function creation is forbidden');
|
|
30
|
+
}
|
|
31
|
+
let func;
|
|
32
|
+
if (name === undefined) {
|
|
33
|
+
func = (...args) => {
|
|
34
|
+
const vars = generateArgs(argNames, args);
|
|
35
|
+
const res = executeTree(ticks, context, parsed, scope === undefined ? [] : [new utils.Scope(scope, vars)]);
|
|
36
|
+
return res.result;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
func = function sandboxedObject(...args) {
|
|
41
|
+
const vars = generateArgs(argNames, args);
|
|
42
|
+
const res = executeTree(ticks, context, parsed, scope === undefined ? [] : [new utils.Scope(scope, vars, this)]);
|
|
43
|
+
return res.result;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
context.registerSandboxFunction(func);
|
|
47
|
+
context.ctx.sandboxedFunctions.add(func);
|
|
48
|
+
return func;
|
|
49
|
+
}
|
|
50
|
+
function createFunctionAsync(argNames, parsed, ticks, context, scope, name) {
|
|
51
|
+
if (context.ctx.options.forbidFunctionCreation) {
|
|
52
|
+
throw new utils.SandboxCapabilityError('Function creation is forbidden');
|
|
53
|
+
}
|
|
54
|
+
if (!context.ctx.prototypeWhitelist?.has(Promise.prototype)) {
|
|
55
|
+
throw new utils.SandboxCapabilityError('Async/await not permitted');
|
|
56
|
+
}
|
|
57
|
+
let func;
|
|
58
|
+
if (name === undefined) {
|
|
59
|
+
func = async (...args) => {
|
|
60
|
+
const vars = generateArgs(argNames, args);
|
|
61
|
+
const res = await executeTreeAsync(ticks, context, parsed, scope === undefined ? [] : [new utils.Scope(scope, vars)]);
|
|
62
|
+
return res.result;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
func = async function sandboxedObject(...args) {
|
|
67
|
+
const vars = generateArgs(argNames, args);
|
|
68
|
+
const res = await executeTreeAsync(ticks, context, parsed, scope === undefined ? [] : [new utils.Scope(scope, vars, this)]);
|
|
69
|
+
return res.result;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
context.registerSandboxFunction(func);
|
|
73
|
+
context.ctx.sandboxedFunctions.add(func);
|
|
74
|
+
return func;
|
|
75
|
+
}
|
|
76
|
+
function assignCheck(obj, context, op = 'assign') {
|
|
77
|
+
if (obj.context === undefined) {
|
|
78
|
+
throw new ReferenceError(`Cannot ${op} value to undefined.`);
|
|
79
|
+
}
|
|
80
|
+
if (obj.isConst) {
|
|
81
|
+
throw new TypeError(`Assignment to constant variable.`);
|
|
82
|
+
}
|
|
83
|
+
if (obj.isGlobal) {
|
|
84
|
+
throw new utils.SandboxAccessError(`Cannot ${op} property '${obj.prop.toString()}' of a global object`);
|
|
85
|
+
}
|
|
86
|
+
if (obj.context === null) {
|
|
87
|
+
throw new TypeError('Cannot set properties of null');
|
|
88
|
+
}
|
|
89
|
+
if (typeof obj.context[obj.prop] === 'function' &&
|
|
90
|
+
!utils.hasOwnProperty(obj.context, obj.prop)) {
|
|
91
|
+
throw new utils.SandboxAccessError(`Override prototype property '${obj.prop.toString()}' not allowed`);
|
|
92
|
+
}
|
|
93
|
+
if (op === 'delete') {
|
|
94
|
+
if (utils.hasOwnProperty(obj.context, obj.prop)) {
|
|
95
|
+
context.changeSubscriptions
|
|
96
|
+
.get(obj.context)
|
|
97
|
+
?.forEach((cb) => cb({ type: 'delete', prop: obj.prop.toString() }));
|
|
98
|
+
context.changeSubscriptionsGlobal
|
|
99
|
+
.get(obj.context)
|
|
100
|
+
?.forEach((cb) => cb({ type: 'delete', prop: obj.prop.toString() }));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (utils.hasOwnProperty(obj.context, obj.prop)) {
|
|
104
|
+
context.setSubscriptions
|
|
105
|
+
.get(obj.context)
|
|
106
|
+
?.get(obj.prop.toString())
|
|
107
|
+
?.forEach((cb) => cb({
|
|
108
|
+
type: 'replace',
|
|
109
|
+
}));
|
|
110
|
+
context.setSubscriptionsGlobal
|
|
111
|
+
.get(obj.context)
|
|
112
|
+
?.get(obj.prop.toString())
|
|
113
|
+
?.forEach((cb) => cb({
|
|
114
|
+
type: 'replace',
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
context.changeSubscriptions
|
|
119
|
+
.get(obj.context)
|
|
120
|
+
?.forEach((cb) => cb({ type: 'create', prop: obj.prop.toString() }));
|
|
121
|
+
context.changeSubscriptionsGlobal
|
|
122
|
+
.get(obj.context)
|
|
123
|
+
?.forEach((cb) => cb({ type: 'create', prop: obj.prop.toString() }));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const arrayChange = new Set([
|
|
127
|
+
[].push,
|
|
128
|
+
[].pop,
|
|
129
|
+
[].shift,
|
|
130
|
+
[].unshift,
|
|
131
|
+
[].splice,
|
|
132
|
+
[].reverse,
|
|
133
|
+
[].sort,
|
|
134
|
+
[].copyWithin,
|
|
135
|
+
]);
|
|
136
|
+
class KeyVal {
|
|
137
|
+
constructor(key, val) {
|
|
138
|
+
this.key = key;
|
|
139
|
+
this.val = val;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
class SpreadObject {
|
|
143
|
+
constructor(item) {
|
|
144
|
+
this.item = item;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
class SpreadArray {
|
|
148
|
+
constructor(item) {
|
|
149
|
+
this.item = item;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
class If {
|
|
153
|
+
constructor(t, f) {
|
|
154
|
+
this.t = t;
|
|
155
|
+
this.f = f;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const literalRegex = /(\$\$)*(\$)?\${(\d+)}/g;
|
|
159
|
+
const ops = new Map();
|
|
160
|
+
function addOps(type, cb) {
|
|
161
|
+
ops.set(type, cb);
|
|
162
|
+
}
|
|
163
|
+
const prorptyKeyTypes = ['string', 'number', 'symbol'];
|
|
164
|
+
function isPropertyKey(val) {
|
|
165
|
+
return prorptyKeyTypes.includes(typeof val);
|
|
166
|
+
}
|
|
167
|
+
function hasPossibleProperties(val) {
|
|
168
|
+
return val !== null && val !== undefined;
|
|
169
|
+
}
|
|
170
|
+
addOps(1 /* LispType.Prop */, ({ done, a, b, obj, context, scope }) => {
|
|
171
|
+
if (a === null) {
|
|
172
|
+
throw new TypeError(`Cannot read properties of null (reading '${b?.toString()}')`);
|
|
173
|
+
}
|
|
174
|
+
if (!isPropertyKey(b)) {
|
|
175
|
+
b = `${b}`;
|
|
176
|
+
}
|
|
177
|
+
if (a === undefined && obj === undefined && typeof b === 'string') {
|
|
178
|
+
// is variable access
|
|
179
|
+
const prop = scope.get(b);
|
|
180
|
+
if (prop.context === context.ctx.sandboxGlobal) {
|
|
181
|
+
if (context.ctx.options.audit) {
|
|
182
|
+
context.ctx.auditReport?.globalsAccess.add(b);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const val = prop.context ? prop.context[prop.prop] : undefined;
|
|
186
|
+
const p = getGlobalProp(val, context, prop) || prop;
|
|
187
|
+
done(undefined, p);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
else if (a === undefined) {
|
|
191
|
+
throw new TypeError(`Cannot read properties of undefined (reading '${b.toString()}')`);
|
|
192
|
+
}
|
|
193
|
+
if (!hasPossibleProperties(a)) {
|
|
194
|
+
done(undefined, new utils.Prop(undefined, b));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const prototypeAccess = typeof a === 'function' || !utils.hasOwnProperty(a, b);
|
|
198
|
+
if (context.ctx.options.audit && prototypeAccess) {
|
|
199
|
+
let prot = Object.getPrototypeOf(a);
|
|
200
|
+
do {
|
|
201
|
+
if (utils.hasOwnProperty(prot, b)) {
|
|
202
|
+
if (context.ctx.auditReport &&
|
|
203
|
+
!context.ctx.auditReport.prototypeAccess[prot.constructor.name]) {
|
|
204
|
+
context.ctx.auditReport.prototypeAccess[prot.constructor.name] = new Set();
|
|
205
|
+
}
|
|
206
|
+
context.ctx.auditReport?.prototypeAccess[prot.constructor.name].add(b);
|
|
207
|
+
}
|
|
208
|
+
} while ((prot = Object.getPrototypeOf(prot)));
|
|
209
|
+
}
|
|
210
|
+
if (prototypeAccess) {
|
|
211
|
+
if (typeof a === 'function') {
|
|
212
|
+
if (utils.hasOwnProperty(a, b)) {
|
|
213
|
+
const whitelist = context.ctx.prototypeWhitelist.get(a.prototype);
|
|
214
|
+
const replace = context.ctx.options.prototypeReplacements.get(a);
|
|
215
|
+
if (replace) {
|
|
216
|
+
done(undefined, new utils.Prop(replace(a, true), b));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!(whitelist && (!whitelist.size || whitelist.has(b))) &&
|
|
220
|
+
!context.ctx.sandboxedFunctions.has(a)) {
|
|
221
|
+
throw new utils.SandboxAccessError(`Static method or property access not permitted: ${a.name}.${b.toString()}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Fast path: check own properties of `a` first (handles static methods like Body.json)
|
|
226
|
+
if (utils.hasOwnProperty(a, b)) {
|
|
227
|
+
const replace = context.ctx.options.prototypeReplacements.get(a);
|
|
228
|
+
if (replace) {
|
|
229
|
+
done(undefined, new utils.Prop(replace(a, true), b));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (context.ctx.sandboxedFunctions.has(a)) {
|
|
233
|
+
done(undefined, new utils.Prop(a, b, false, false));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Check if constructor or any ancestor is whitelisted
|
|
237
|
+
let ctorProt = a.prototype;
|
|
238
|
+
while (ctorProt !== null) {
|
|
239
|
+
const whitelist = context.ctx.prototypeWhitelist.get(ctorProt);
|
|
240
|
+
if (whitelist && (!whitelist.size || whitelist.has(b))) {
|
|
241
|
+
done(undefined, new utils.Prop(a, b, false, false));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
ctorProt = Object.getPrototypeOf(ctorProt);
|
|
245
|
+
}
|
|
246
|
+
if (typeof a === 'function') {
|
|
247
|
+
// Constructor not whitelisted, throw
|
|
248
|
+
throw new utils.SandboxAccessError(`Method or property access not permitted: ${a.name}.${b.toString()}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
let prot = a;
|
|
252
|
+
while ((prot = Object.getPrototypeOf(prot))) {
|
|
253
|
+
if (utils.hasOwnProperty(prot, b) || b === '__proto__') {
|
|
254
|
+
const replace = context.ctx.options.prototypeReplacements.get(prot.constructor);
|
|
255
|
+
if (replace) {
|
|
256
|
+
done(undefined, new utils.Prop(replace(a, false), b));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (context.ctx.sandboxedFunctions.has(prot.constructor)) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
// Check if this constructor or any ancestor in its prototype chain is whitelisted
|
|
263
|
+
let ctorProt = prot.constructor;
|
|
264
|
+
let whitelisted = false;
|
|
265
|
+
while (ctorProt !== null) {
|
|
266
|
+
const whitelist = context.ctx.prototypeWhitelist.get(ctorProt);
|
|
267
|
+
if (whitelist && (!whitelist.size || whitelist.has(b))) {
|
|
268
|
+
whitelisted = true;
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
ctorProt = Object.getPrototypeOf(ctorProt);
|
|
272
|
+
}
|
|
273
|
+
if (whitelisted) {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
if (b === '__proto__') {
|
|
277
|
+
throw new utils.SandboxAccessError(`Access to prototype of global object is not permitted`);
|
|
278
|
+
}
|
|
279
|
+
throw new utils.SandboxAccessError(`Method or property access not permitted: ${prot.constructor.name}.${b.toString()}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const val = a[b];
|
|
284
|
+
if (typeof a === 'function') {
|
|
285
|
+
if (b === 'prototype' && !context.ctx.sandboxedFunctions.has(a)) {
|
|
286
|
+
throw new utils.SandboxAccessError(`Access to prototype of global object is not permitted`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (b === '__proto__' && !context.ctx.sandboxedFunctions.has(val?.constructor)) {
|
|
290
|
+
throw new utils.SandboxAccessError(`Access to prototype of global object is not permitted`);
|
|
291
|
+
}
|
|
292
|
+
const p = getGlobalProp(val, context, new utils.Prop(a, b, false, false));
|
|
293
|
+
if (p) {
|
|
294
|
+
done(undefined, p);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const g = (obj instanceof utils.Prop && obj.isGlobal) ||
|
|
298
|
+
(typeof a === 'function' && !context.ctx.sandboxedFunctions.has(a)) ||
|
|
299
|
+
context.ctx.globalsWhitelist.has(a);
|
|
300
|
+
done(undefined, new utils.Prop(a, b, false, g, false));
|
|
301
|
+
});
|
|
302
|
+
function getGlobalProp(val, context, prop) {
|
|
303
|
+
if (!val)
|
|
304
|
+
return;
|
|
305
|
+
const isFunc = typeof val === 'function';
|
|
306
|
+
if (val instanceof utils.Prop) {
|
|
307
|
+
if (!prop) {
|
|
308
|
+
prop = val;
|
|
309
|
+
}
|
|
310
|
+
val = val.get(context);
|
|
311
|
+
}
|
|
312
|
+
const p = prop?.prop || 'prop';
|
|
313
|
+
if (val === globalThis) {
|
|
314
|
+
return new utils.Prop({
|
|
315
|
+
[p]: context.ctx.sandboxGlobal,
|
|
316
|
+
}, p, prop?.isConst || false, false, prop?.isVariable || false);
|
|
317
|
+
}
|
|
318
|
+
const evl = isFunc && context.evals.get(val);
|
|
319
|
+
if (evl) {
|
|
320
|
+
return new utils.Prop({
|
|
321
|
+
[p]: evl,
|
|
322
|
+
}, p, prop?.isConst || false, true, prop?.isVariable || false);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function sanitizeArray(val, context, cache = new WeakSet()) {
|
|
326
|
+
if (!Array.isArray(val))
|
|
327
|
+
return val;
|
|
328
|
+
if (cache.has(val))
|
|
329
|
+
return val;
|
|
330
|
+
cache.add(val);
|
|
331
|
+
for (let i = 0; i < val.length; i++) {
|
|
332
|
+
const item = val[i];
|
|
333
|
+
if (item === globalThis) {
|
|
334
|
+
val[i] = context.ctx.sandboxGlobal;
|
|
335
|
+
}
|
|
336
|
+
else if (typeof item === 'function') {
|
|
337
|
+
const replacement = context.evals.get(item);
|
|
338
|
+
if (replacement) {
|
|
339
|
+
val[i] = replacement;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
sanitizeArray(item, context, cache);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return val;
|
|
347
|
+
}
|
|
348
|
+
addOps(5 /* LispType.Call */, ({ done, a, b, obj, context }) => {
|
|
349
|
+
if (context.ctx.options.forbidFunctionCalls)
|
|
350
|
+
throw new utils.SandboxCapabilityError('Function invocations are not allowed');
|
|
351
|
+
if (typeof a !== 'function') {
|
|
352
|
+
throw new TypeError(`${typeof obj?.prop === 'symbol' ? 'Symbol' : obj?.prop} is not a function`);
|
|
353
|
+
}
|
|
354
|
+
const vals = b
|
|
355
|
+
.map((item) => {
|
|
356
|
+
if (item instanceof SpreadArray) {
|
|
357
|
+
return [...item.item];
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
return [item];
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
.flat()
|
|
364
|
+
.map((item) => valueOrProp(item, context));
|
|
365
|
+
if (typeof obj === 'function') {
|
|
366
|
+
const evl = context.evals.get(obj);
|
|
367
|
+
let ret = evl ? evl(obj, ...vals) : obj(...vals);
|
|
368
|
+
ret = getGlobalProp(ret, context) || ret;
|
|
369
|
+
sanitizeArray(ret, context);
|
|
370
|
+
done(undefined, ret);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (obj.context[obj.prop] === JSON.stringify && context.getSubscriptions.size) {
|
|
374
|
+
const cache = new Set();
|
|
375
|
+
const recurse = (x) => {
|
|
376
|
+
if (!x || !(typeof x === 'object') || cache.has(x))
|
|
377
|
+
return;
|
|
378
|
+
cache.add(x);
|
|
379
|
+
for (const y of Object.keys(x)) {
|
|
380
|
+
context.getSubscriptions.forEach((cb) => cb(x, y));
|
|
381
|
+
recurse(x[y]);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
recurse(vals[0]);
|
|
385
|
+
}
|
|
386
|
+
if (obj.context instanceof Array &&
|
|
387
|
+
arrayChange.has(obj.context[obj.prop]) &&
|
|
388
|
+
(context.changeSubscriptions.get(obj.context) ||
|
|
389
|
+
context.changeSubscriptionsGlobal.get(obj.context))) {
|
|
390
|
+
let change;
|
|
391
|
+
let changed = false;
|
|
392
|
+
if (obj.prop === 'push') {
|
|
393
|
+
change = {
|
|
394
|
+
type: 'push',
|
|
395
|
+
added: vals,
|
|
396
|
+
};
|
|
397
|
+
changed = !!vals.length;
|
|
398
|
+
}
|
|
399
|
+
else if (obj.prop === 'pop') {
|
|
400
|
+
change = {
|
|
401
|
+
type: 'pop',
|
|
402
|
+
removed: obj.context.slice(-1),
|
|
403
|
+
};
|
|
404
|
+
changed = !!change.removed.length;
|
|
405
|
+
}
|
|
406
|
+
else if (obj.prop === 'shift') {
|
|
407
|
+
change = {
|
|
408
|
+
type: 'shift',
|
|
409
|
+
removed: obj.context.slice(0, 1),
|
|
410
|
+
};
|
|
411
|
+
changed = !!change.removed.length;
|
|
412
|
+
}
|
|
413
|
+
else if (obj.prop === 'unshift') {
|
|
414
|
+
change = {
|
|
415
|
+
type: 'unshift',
|
|
416
|
+
added: vals,
|
|
417
|
+
};
|
|
418
|
+
changed = !!vals.length;
|
|
419
|
+
}
|
|
420
|
+
else if (obj.prop === 'splice') {
|
|
421
|
+
change = {
|
|
422
|
+
type: 'splice',
|
|
423
|
+
startIndex: vals[0],
|
|
424
|
+
deleteCount: vals[1] === undefined ? obj.context.length : vals[1],
|
|
425
|
+
added: vals.slice(2),
|
|
426
|
+
removed: obj.context.slice(vals[0], vals[1] === undefined ? undefined : vals[0] + vals[1]),
|
|
427
|
+
};
|
|
428
|
+
changed = !!change.added.length || !!change.removed.length;
|
|
429
|
+
}
|
|
430
|
+
else if (obj.prop === 'reverse' || obj.prop === 'sort') {
|
|
431
|
+
change = { type: obj.prop };
|
|
432
|
+
changed = !!obj.context.length;
|
|
433
|
+
}
|
|
434
|
+
else if (obj.prop === 'copyWithin') {
|
|
435
|
+
const len = vals[2] === undefined
|
|
436
|
+
? obj.context.length - vals[1]
|
|
437
|
+
: Math.min(obj.context.length, vals[2] - vals[1]);
|
|
438
|
+
change = {
|
|
439
|
+
type: 'copyWithin',
|
|
440
|
+
startIndex: vals[0],
|
|
441
|
+
endIndex: vals[0] + len,
|
|
442
|
+
added: obj.context.slice(vals[1], vals[1] + len),
|
|
443
|
+
removed: obj.context.slice(vals[0], vals[0] + len),
|
|
444
|
+
};
|
|
445
|
+
changed = !!change.added.length || !!change.removed.length;
|
|
446
|
+
}
|
|
447
|
+
if (changed) {
|
|
448
|
+
context.changeSubscriptions.get(obj.context)?.forEach((cb) => cb(change));
|
|
449
|
+
context.changeSubscriptionsGlobal.get(obj.context)?.forEach((cb) => cb(change));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
obj.get(context);
|
|
453
|
+
const evl = context.evals.get(obj.context[obj.prop]);
|
|
454
|
+
let ret = evl ? evl(obj.context[obj.prop], ...vals) : obj.context[obj.prop](...vals);
|
|
455
|
+
ret = getGlobalProp(ret, context) || ret;
|
|
456
|
+
sanitizeArray(ret, context);
|
|
457
|
+
done(undefined, ret);
|
|
458
|
+
});
|
|
459
|
+
addOps(22 /* LispType.CreateObject */, ({ done, b }) => {
|
|
460
|
+
let res = {};
|
|
461
|
+
for (const item of b) {
|
|
462
|
+
if (item.key instanceof SpreadObject) {
|
|
463
|
+
res = { ...res, ...item.key.item };
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
res[item.key] = item.val;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
done(undefined, res);
|
|
470
|
+
});
|
|
471
|
+
addOps(6 /* LispType.KeyVal */, ({ done, a, b }) => done(undefined, new KeyVal(a, b)));
|
|
472
|
+
addOps(12 /* LispType.CreateArray */, ({ done, b, context }) => {
|
|
473
|
+
const items = b
|
|
474
|
+
.map((item) => {
|
|
475
|
+
if (item instanceof SpreadArray) {
|
|
476
|
+
return [...item.item];
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
return [item];
|
|
480
|
+
}
|
|
481
|
+
})
|
|
482
|
+
.flat()
|
|
483
|
+
.map((item) => valueOrProp(item, context));
|
|
484
|
+
done(undefined, items);
|
|
485
|
+
});
|
|
486
|
+
addOps(23 /* LispType.Group */, ({ done, b }) => done(undefined, b));
|
|
487
|
+
addOps(35 /* LispType.GlobalSymbol */, ({ done, b }) => {
|
|
488
|
+
switch (b) {
|
|
489
|
+
case 'true':
|
|
490
|
+
return done(undefined, true);
|
|
491
|
+
case 'false':
|
|
492
|
+
return done(undefined, false);
|
|
493
|
+
case 'null':
|
|
494
|
+
return done(undefined, null);
|
|
495
|
+
case 'undefined':
|
|
496
|
+
return done(undefined, undefined);
|
|
497
|
+
case 'NaN':
|
|
498
|
+
return done(undefined, NaN);
|
|
499
|
+
case 'Infinity':
|
|
500
|
+
return done(undefined, Infinity);
|
|
501
|
+
}
|
|
502
|
+
done(new Error('Unknown symbol: ' + b));
|
|
503
|
+
});
|
|
504
|
+
addOps(7 /* LispType.Number */, ({ done, b }) => done(undefined, Number(b.replace(/_/g, ''))));
|
|
505
|
+
addOps(83 /* LispType.BigInt */, ({ done, b }) => done(undefined, BigInt(b.replace(/_/g, ''))));
|
|
506
|
+
addOps(2 /* LispType.StringIndex */, ({ done, b, context }) => done(undefined, context.constants.strings[parseInt(b)]));
|
|
507
|
+
addOps(85 /* LispType.RegexIndex */, ({ done, b, context }) => {
|
|
508
|
+
const reg = context.constants.regexes[parseInt(b)];
|
|
509
|
+
if (!context.ctx.globalsWhitelist.has(RegExp)) {
|
|
510
|
+
throw new utils.SandboxCapabilityError('Regex not permitted');
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
done(undefined, new RegExp(reg.regex, reg.flags));
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
addOps(84 /* LispType.LiteralIndex */, ({ exec, done, ticks, b, context, scope }) => {
|
|
517
|
+
const item = context.constants.literals[parseInt(b)];
|
|
518
|
+
const [, name, js] = item;
|
|
519
|
+
const found = [];
|
|
520
|
+
let f;
|
|
521
|
+
const resnums = [];
|
|
522
|
+
while ((f = literalRegex.exec(name))) {
|
|
523
|
+
if (!f[2]) {
|
|
524
|
+
found.push(js[parseInt(f[3], 10)]);
|
|
525
|
+
resnums.push(f[3]);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
exec(ticks, found, scope, context, (...args) => {
|
|
529
|
+
const reses = {};
|
|
530
|
+
if (args.length === 1) {
|
|
531
|
+
done(args[0]);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
const processed = args[1];
|
|
535
|
+
for (const i of Object.keys(processed)) {
|
|
536
|
+
const num = resnums[i];
|
|
537
|
+
reses[num] = processed[i];
|
|
538
|
+
}
|
|
539
|
+
done(undefined, name.replace(/(\\\\)*(\\)?\${(\d+)}/g, (match, $$, $, num) => {
|
|
540
|
+
if ($)
|
|
541
|
+
return match;
|
|
542
|
+
const res = reses[num];
|
|
543
|
+
return ($$ ? $$ : '') + `${valueOrProp(res, context)}`;
|
|
544
|
+
}));
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
addOps(18 /* LispType.SpreadArray */, ({ done, b }) => {
|
|
548
|
+
done(undefined, new SpreadArray(b));
|
|
549
|
+
});
|
|
550
|
+
addOps(17 /* LispType.SpreadObject */, ({ done, b }) => {
|
|
551
|
+
done(undefined, new SpreadObject(b));
|
|
552
|
+
});
|
|
553
|
+
addOps(24 /* LispType.Not */, ({ done, b }) => done(undefined, !b));
|
|
554
|
+
addOps(64 /* LispType.Inverse */, ({ done, b }) => done(undefined, ~b));
|
|
555
|
+
addOps(25 /* LispType.IncrementBefore */, ({ done, obj, context }) => {
|
|
556
|
+
assignCheck(obj, context);
|
|
557
|
+
done(undefined, ++obj.context[obj.prop]);
|
|
558
|
+
});
|
|
559
|
+
addOps(26 /* LispType.IncrementAfter */, ({ done, obj, context }) => {
|
|
560
|
+
assignCheck(obj, context);
|
|
561
|
+
done(undefined, obj.context[obj.prop]++);
|
|
562
|
+
});
|
|
563
|
+
addOps(27 /* LispType.DecrementBefore */, ({ done, obj, context }) => {
|
|
564
|
+
assignCheck(obj, context);
|
|
565
|
+
done(undefined, --obj.context[obj.prop]);
|
|
566
|
+
});
|
|
567
|
+
addOps(28 /* LispType.DecrementAfter */, ({ done, obj, context }) => {
|
|
568
|
+
assignCheck(obj, context);
|
|
569
|
+
done(undefined, obj.context[obj.prop]--);
|
|
570
|
+
});
|
|
571
|
+
addOps(9 /* LispType.Assign */, ({ done, b, obj, context, scope, bobj }) => {
|
|
572
|
+
assignCheck(obj, context);
|
|
573
|
+
obj.isGlobal = bobj?.isGlobal || false;
|
|
574
|
+
if (obj.isVariable) {
|
|
575
|
+
const s = scope.getWhereValScope(obj.prop, obj.prop === 'this');
|
|
576
|
+
if (s === null) {
|
|
577
|
+
throw new ReferenceError(`Cannot assign to undeclared variable '${obj.prop.toString()}'`);
|
|
578
|
+
}
|
|
579
|
+
s.set(obj.prop, b);
|
|
580
|
+
if (obj.isGlobal) {
|
|
581
|
+
s.globals[obj.prop.toString()] = true;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
delete s.globals[obj.prop.toString()];
|
|
585
|
+
}
|
|
586
|
+
done(undefined, b);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
done(undefined, (obj.context[obj.prop] = b));
|
|
590
|
+
});
|
|
591
|
+
addOps(66 /* LispType.AddEquals */, ({ done, b, obj, context }) => {
|
|
592
|
+
assignCheck(obj, context);
|
|
593
|
+
done(undefined, (obj.context[obj.prop] += b));
|
|
594
|
+
});
|
|
595
|
+
addOps(65 /* LispType.SubractEquals */, ({ done, b, obj, context }) => {
|
|
596
|
+
assignCheck(obj, context);
|
|
597
|
+
done(undefined, (obj.context[obj.prop] -= b));
|
|
598
|
+
});
|
|
599
|
+
addOps(67 /* LispType.DivideEquals */, ({ done, b, obj, context }) => {
|
|
600
|
+
assignCheck(obj, context);
|
|
601
|
+
done(undefined, (obj.context[obj.prop] /= b));
|
|
602
|
+
});
|
|
603
|
+
addOps(69 /* LispType.MultiplyEquals */, ({ done, b, obj, context }) => {
|
|
604
|
+
assignCheck(obj, context);
|
|
605
|
+
done(undefined, (obj.context[obj.prop] *= b));
|
|
606
|
+
});
|
|
607
|
+
addOps(68 /* LispType.PowerEquals */, ({ done, b, obj, context }) => {
|
|
608
|
+
assignCheck(obj, context);
|
|
609
|
+
done(undefined, (obj.context[obj.prop] **= b));
|
|
610
|
+
});
|
|
611
|
+
addOps(70 /* LispType.ModulusEquals */, ({ done, b, obj, context }) => {
|
|
612
|
+
assignCheck(obj, context);
|
|
613
|
+
done(undefined, (obj.context[obj.prop] %= b));
|
|
614
|
+
});
|
|
615
|
+
addOps(71 /* LispType.BitNegateEquals */, ({ done, b, obj, context }) => {
|
|
616
|
+
assignCheck(obj, context);
|
|
617
|
+
done(undefined, (obj.context[obj.prop] ^= b));
|
|
618
|
+
});
|
|
619
|
+
addOps(72 /* LispType.BitAndEquals */, ({ done, b, obj, context }) => {
|
|
620
|
+
assignCheck(obj, context);
|
|
621
|
+
done(undefined, (obj.context[obj.prop] &= b));
|
|
622
|
+
});
|
|
623
|
+
addOps(73 /* LispType.BitOrEquals */, ({ done, b, obj, context }) => {
|
|
624
|
+
assignCheck(obj, context);
|
|
625
|
+
done(undefined, (obj.context[obj.prop] |= b));
|
|
626
|
+
});
|
|
627
|
+
addOps(76 /* LispType.ShiftLeftEquals */, ({ done, b, obj, context }) => {
|
|
628
|
+
assignCheck(obj, context);
|
|
629
|
+
done(undefined, (obj.context[obj.prop] <<= b));
|
|
630
|
+
});
|
|
631
|
+
addOps(75 /* LispType.ShiftRightEquals */, ({ done, b, obj, context }) => {
|
|
632
|
+
assignCheck(obj, context);
|
|
633
|
+
done(undefined, (obj.context[obj.prop] >>= b));
|
|
634
|
+
});
|
|
635
|
+
addOps(74 /* LispType.UnsignedShiftRightEquals */, ({ done, b, obj, context }) => {
|
|
636
|
+
assignCheck(obj, context);
|
|
637
|
+
done(undefined, (obj.context[obj.prop] >>>= b));
|
|
638
|
+
});
|
|
639
|
+
addOps(90 /* LispType.AndEquals */, ({ done, b, obj, context }) => {
|
|
640
|
+
var _a, _b;
|
|
641
|
+
assignCheck(obj, context);
|
|
642
|
+
done(undefined, ((_a = obj.context)[_b = obj.prop] && (_a[_b] = b)));
|
|
643
|
+
});
|
|
644
|
+
addOps(91 /* LispType.OrEquals */, ({ done, b, obj, context }) => {
|
|
645
|
+
var _a, _b;
|
|
646
|
+
assignCheck(obj, context);
|
|
647
|
+
done(undefined, ((_a = obj.context)[_b = obj.prop] || (_a[_b] = b)));
|
|
648
|
+
});
|
|
649
|
+
addOps(92 /* LispType.NullishCoalescingEquals */, ({ done, b, obj, context }) => {
|
|
650
|
+
var _a, _b;
|
|
651
|
+
assignCheck(obj, context);
|
|
652
|
+
done(undefined, ((_a = obj.context)[_b = obj.prop] ?? (_a[_b] = b)));
|
|
653
|
+
});
|
|
654
|
+
addOps(57 /* LispType.LargerThan */, ({ done, a, b }) => done(undefined, a > b));
|
|
655
|
+
addOps(56 /* LispType.SmallerThan */, ({ done, a, b }) => done(undefined, a < b));
|
|
656
|
+
addOps(55 /* LispType.LargerEqualThan */, ({ done, a, b }) => done(undefined, a >= b));
|
|
657
|
+
addOps(54 /* LispType.SmallerEqualThan */, ({ done, a, b }) => done(undefined, a <= b));
|
|
658
|
+
addOps(52 /* LispType.Equal */, ({ done, a, b }) => done(undefined, a == b));
|
|
659
|
+
addOps(32 /* LispType.StrictEqual */, ({ done, a, b }) => done(undefined, a === b));
|
|
660
|
+
addOps(53 /* LispType.NotEqual */, ({ done, a, b }) => done(undefined, a != b));
|
|
661
|
+
addOps(31 /* LispType.StrictNotEqual */, ({ done, a, b }) => done(undefined, a !== b));
|
|
662
|
+
addOps(29 /* LispType.And */, ({ done, a, b }) => done(undefined, a && b));
|
|
663
|
+
addOps(30 /* LispType.Or */, ({ done, a, b }) => done(undefined, a || b));
|
|
664
|
+
addOps(89 /* LispType.NullishCoalescing */, ({ done, a, b }) => done(undefined, a ?? b));
|
|
665
|
+
addOps(77 /* LispType.BitAnd */, ({ done, a, b }) => done(undefined, a & b));
|
|
666
|
+
addOps(78 /* LispType.BitOr */, ({ done, a, b }) => done(undefined, a | b));
|
|
667
|
+
addOps(33 /* LispType.Plus */, ({ done, a, b }) => done(undefined, a + b));
|
|
668
|
+
addOps(47 /* LispType.Minus */, ({ done, a, b }) => done(undefined, a - b));
|
|
669
|
+
addOps(59 /* LispType.Positive */, ({ done, b }) => done(undefined, +b));
|
|
670
|
+
addOps(58 /* LispType.Negative */, ({ done, b }) => done(undefined, -b));
|
|
671
|
+
addOps(48 /* LispType.Divide */, ({ done, a, b }) => done(undefined, a / b));
|
|
672
|
+
addOps(49 /* LispType.Power */, ({ done, a, b }) => done(undefined, a ** b));
|
|
673
|
+
addOps(79 /* LispType.BitNegate */, ({ done, a, b }) => done(undefined, a ^ b));
|
|
674
|
+
addOps(50 /* LispType.Multiply */, ({ done, a, b }) => done(undefined, a * b));
|
|
675
|
+
addOps(51 /* LispType.Modulus */, ({ done, a, b }) => done(undefined, a % b));
|
|
676
|
+
addOps(80 /* LispType.BitShiftLeft */, ({ done, a, b }) => done(undefined, a << b));
|
|
677
|
+
addOps(81 /* LispType.BitShiftRight */, ({ done, a, b }) => done(undefined, a >> b));
|
|
678
|
+
addOps(82 /* LispType.BitUnsignedShiftRight */, ({ done, a, b }) => done(undefined, a >>> b));
|
|
679
|
+
addOps(60 /* LispType.Typeof */, ({ exec, done, ticks, b, context, scope }) => {
|
|
680
|
+
exec(ticks, b, scope, context, (e, prop) => {
|
|
681
|
+
done(undefined, typeof valueOrProp(prop, context));
|
|
682
|
+
});
|
|
683
|
+
});
|
|
684
|
+
addOps(62 /* LispType.Instanceof */, ({ done, a, b }) => done(undefined, a instanceof b));
|
|
685
|
+
addOps(63 /* LispType.In */, ({ done, a, b }) => done(undefined, a in b));
|
|
686
|
+
addOps(61 /* LispType.Delete */, ({ done, context, bobj }) => {
|
|
687
|
+
if (!(bobj instanceof utils.Prop)) {
|
|
688
|
+
done(undefined, true);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
assignCheck(bobj, context, 'delete');
|
|
692
|
+
if (bobj.isVariable) {
|
|
693
|
+
done(undefined, false);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
done(undefined, delete bobj.context?.[bobj.prop]);
|
|
697
|
+
});
|
|
698
|
+
addOps(8 /* LispType.Return */, ({ done, b }) => done(undefined, b));
|
|
699
|
+
addOps(34 /* LispType.Var */, ({ done, a, b, scope, bobj }) => {
|
|
700
|
+
done(undefined, scope.declare(a, "var" /* VarType.var */, b, bobj?.isGlobal || false));
|
|
701
|
+
});
|
|
702
|
+
addOps(3 /* LispType.Let */, ({ done, a, b, scope, bobj }) => {
|
|
703
|
+
done(undefined, scope.declare(a, "let" /* VarType.let */, b, bobj?.isGlobal || false));
|
|
704
|
+
});
|
|
705
|
+
addOps(4 /* LispType.Const */, ({ done, a, b, scope, bobj }) => {
|
|
706
|
+
done(undefined, scope.declare(a, "const" /* VarType.const */, b, bobj?.isGlobal || false));
|
|
707
|
+
});
|
|
708
|
+
addOps(11 /* LispType.ArrowFunction */, ({ done, ticks, a, b, obj, context, scope }) => {
|
|
709
|
+
a = [...a];
|
|
710
|
+
if (typeof obj[2] === 'string' || obj[2] instanceof utils.CodeString) {
|
|
711
|
+
if (context.allowJit && context.evalContext) {
|
|
712
|
+
obj[2] = b = context.evalContext.lispifyFunction(new utils.CodeString(obj[2]), context.constants);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
throw new utils.SandboxCapabilityError('Unevaluated code detected, JIT not allowed');
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (a.shift()) {
|
|
719
|
+
done(undefined, createFunctionAsync(a, b, ticks, context, scope));
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
done(undefined, createFunction(a, b, ticks, context, scope));
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
addOps(37 /* LispType.Function */, ({ done, ticks, a, b, obj, context, scope }) => {
|
|
726
|
+
if (typeof obj[2] === 'string' || obj[2] instanceof utils.CodeString) {
|
|
727
|
+
if (context.allowJit && context.evalContext) {
|
|
728
|
+
obj[2] = b = context.evalContext.lispifyFunction(new utils.CodeString(obj[2]), context.constants);
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
throw new utils.SandboxCapabilityError('Unevaluated code detected, JIT not allowed');
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const isAsync = a.shift();
|
|
735
|
+
const name = a.shift();
|
|
736
|
+
let func;
|
|
737
|
+
if (isAsync === 88 /* LispType.True */) {
|
|
738
|
+
func = createFunctionAsync(a, b, ticks, context, scope, name);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
func = createFunction(a, b, ticks, context, scope, name);
|
|
742
|
+
}
|
|
743
|
+
if (name) {
|
|
744
|
+
scope.declare(name, "var" /* VarType.var */, func);
|
|
745
|
+
}
|
|
746
|
+
done(undefined, func);
|
|
747
|
+
});
|
|
748
|
+
addOps(10 /* LispType.InlineFunction */, ({ done, ticks, a, b, obj, context, scope }) => {
|
|
749
|
+
if (typeof obj[2] === 'string' || obj[2] instanceof utils.CodeString) {
|
|
750
|
+
if (context.allowJit && context.evalContext) {
|
|
751
|
+
obj[2] = b = context.evalContext.lispifyFunction(new utils.CodeString(obj[2]), context.constants);
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
throw new utils.SandboxCapabilityError('Unevaluated code detected, JIT not allowed');
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
const isAsync = a.shift();
|
|
758
|
+
const name = a.shift();
|
|
759
|
+
if (name) {
|
|
760
|
+
scope = new utils.Scope(scope, {});
|
|
761
|
+
}
|
|
762
|
+
let func;
|
|
763
|
+
if (isAsync === 88 /* LispType.True */) {
|
|
764
|
+
func = createFunctionAsync(a, b, ticks, context, scope, name);
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
func = createFunction(a, b, ticks, context, scope, name);
|
|
768
|
+
}
|
|
769
|
+
if (name) {
|
|
770
|
+
scope.declare(name, "let" /* VarType.let */, func);
|
|
771
|
+
}
|
|
772
|
+
done(undefined, func);
|
|
773
|
+
});
|
|
774
|
+
addOps(38 /* LispType.Loop */, ({ exec, done, ticks, a, b, context, scope }) => {
|
|
775
|
+
const [checkFirst, startInternal, getIterator, startStep, step, condition, beforeStep] = a;
|
|
776
|
+
let loop = true;
|
|
777
|
+
const loopScope = new utils.Scope(scope, {});
|
|
778
|
+
const internalVars = {
|
|
779
|
+
$$obj: undefined,
|
|
780
|
+
};
|
|
781
|
+
const interalScope = new utils.Scope(loopScope, internalVars);
|
|
782
|
+
if (exec === execAsync) {
|
|
783
|
+
(async () => {
|
|
784
|
+
let ad;
|
|
785
|
+
ad = asyncDone((d) => exec(ticks, startStep, loopScope, context, d));
|
|
786
|
+
internalVars['$$obj'] =
|
|
787
|
+
(ad = asyncDone((d) => exec(ticks, getIterator, loopScope, context, d))).isInstant === true
|
|
788
|
+
? ad.instant
|
|
789
|
+
: (await ad.p).result;
|
|
790
|
+
ad = asyncDone((d) => exec(ticks, startInternal, interalScope, context, d));
|
|
791
|
+
if (checkFirst)
|
|
792
|
+
loop =
|
|
793
|
+
(ad = asyncDone((d) => exec(ticks, condition, interalScope, context, d))).isInstant ===
|
|
794
|
+
true
|
|
795
|
+
? ad.instant
|
|
796
|
+
: (await ad.p).result;
|
|
797
|
+
while (loop) {
|
|
798
|
+
const innerLoopVars = {};
|
|
799
|
+
ad = asyncDone((d) => exec(ticks, beforeStep, new utils.Scope(interalScope, innerLoopVars), context, d));
|
|
800
|
+
ad.isInstant === true ? ad.instant : (await ad.p).result;
|
|
801
|
+
const res = await executeTreeAsync(ticks, context, b, [new utils.Scope(loopScope, innerLoopVars)], 'loop');
|
|
802
|
+
if (res instanceof ExecReturn && res.returned) {
|
|
803
|
+
done(undefined, res);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (res instanceof ExecReturn && res.breakLoop) {
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
ad = asyncDone((d) => exec(ticks, step, interalScope, context, d));
|
|
810
|
+
loop =
|
|
811
|
+
(ad = asyncDone((d) => exec(ticks, condition, interalScope, context, d))).isInstant ===
|
|
812
|
+
true
|
|
813
|
+
? ad.instant
|
|
814
|
+
: (await ad.p).result;
|
|
815
|
+
}
|
|
816
|
+
done();
|
|
817
|
+
})().catch(done);
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
syncDone((d) => exec(ticks, startStep, loopScope, context, d));
|
|
821
|
+
internalVars['$$obj'] = syncDone((d) => exec(ticks, getIterator, loopScope, context, d)).result;
|
|
822
|
+
syncDone((d) => exec(ticks, startInternal, interalScope, context, d));
|
|
823
|
+
if (checkFirst)
|
|
824
|
+
loop = syncDone((d) => exec(ticks, condition, interalScope, context, d)).result;
|
|
825
|
+
while (loop) {
|
|
826
|
+
const innerLoopVars = {};
|
|
827
|
+
syncDone((d) => exec(ticks, beforeStep, new utils.Scope(interalScope, innerLoopVars), context, d));
|
|
828
|
+
const res = executeTree(ticks, context, b, [new utils.Scope(loopScope, innerLoopVars)], 'loop');
|
|
829
|
+
if (res instanceof ExecReturn && res.returned) {
|
|
830
|
+
done(undefined, res);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
if (res instanceof ExecReturn && res.breakLoop) {
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
syncDone((d) => exec(ticks, step, interalScope, context, d));
|
|
837
|
+
loop = syncDone((d) => exec(ticks, condition, interalScope, context, d)).result;
|
|
838
|
+
}
|
|
839
|
+
done();
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
addOps(86 /* LispType.LoopAction */, ({ done, a, context, inLoopOrSwitch }) => {
|
|
843
|
+
if ((inLoopOrSwitch === 'switch' && a === 'continue') || !inLoopOrSwitch) {
|
|
844
|
+
throw new TypeError('Illegal ' + a + ' statement');
|
|
845
|
+
}
|
|
846
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, undefined, false, a === 'break', a === 'continue'));
|
|
847
|
+
});
|
|
848
|
+
addOps(13 /* LispType.If */, ({ exec, done, ticks, a, b, context, scope, inLoopOrSwitch }) => {
|
|
849
|
+
exec(ticks, valueOrProp(a, context) ? b.t : b.f, scope, context, done, inLoopOrSwitch);
|
|
850
|
+
});
|
|
851
|
+
addOps(15 /* LispType.InlineIf */, ({ exec, done, ticks, a, b, context, scope }) => {
|
|
852
|
+
exec(ticks, valueOrProp(a, context) ? b.t : b.f, scope, context, done, undefined);
|
|
853
|
+
});
|
|
854
|
+
addOps(16 /* LispType.InlineIfCase */, ({ done, a, b }) => done(undefined, new If(a, b)));
|
|
855
|
+
addOps(14 /* LispType.IfCase */, ({ done, a, b }) => done(undefined, new If(a, b)));
|
|
856
|
+
addOps(40 /* LispType.Switch */, ({ exec, done, ticks, a, b, context, scope }) => {
|
|
857
|
+
exec(ticks, a, scope, context, (...args) => {
|
|
858
|
+
if (args.length === 1) {
|
|
859
|
+
done(args[0]);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
let toTest = args[1];
|
|
863
|
+
toTest = valueOrProp(toTest, context);
|
|
864
|
+
if (exec === execSync) {
|
|
865
|
+
let res;
|
|
866
|
+
let isTrue = false;
|
|
867
|
+
for (const caseItem of b) {
|
|
868
|
+
if (isTrue ||
|
|
869
|
+
(isTrue =
|
|
870
|
+
!caseItem[1] ||
|
|
871
|
+
toTest ===
|
|
872
|
+
valueOrProp(syncDone((d) => exec(ticks, caseItem[1], scope, context, d)).result, context))) {
|
|
873
|
+
if (!caseItem[2])
|
|
874
|
+
continue;
|
|
875
|
+
res = executeTree(ticks, context, caseItem[2], [scope], 'switch');
|
|
876
|
+
if (res.breakLoop)
|
|
877
|
+
break;
|
|
878
|
+
if (res.returned) {
|
|
879
|
+
done(undefined, res);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (!caseItem[1]) {
|
|
883
|
+
// default case
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
done();
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
(async () => {
|
|
892
|
+
let res;
|
|
893
|
+
let isTrue = false;
|
|
894
|
+
for (const caseItem of b) {
|
|
895
|
+
let ad;
|
|
896
|
+
if (isTrue ||
|
|
897
|
+
(isTrue =
|
|
898
|
+
!caseItem[1] ||
|
|
899
|
+
toTest ===
|
|
900
|
+
valueOrProp((ad = asyncDone((d) => exec(ticks, caseItem[1], scope, context, d))).isInstant ===
|
|
901
|
+
true
|
|
902
|
+
? ad.instant
|
|
903
|
+
: (await ad.p).result, context))) {
|
|
904
|
+
if (!caseItem[2])
|
|
905
|
+
continue;
|
|
906
|
+
res = await executeTreeAsync(ticks, context, caseItem[2], [scope], 'switch');
|
|
907
|
+
if (res.breakLoop)
|
|
908
|
+
break;
|
|
909
|
+
if (res.returned) {
|
|
910
|
+
done(undefined, res);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
if (!caseItem[1]) {
|
|
914
|
+
// default case
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
done();
|
|
920
|
+
})().catch(done);
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
});
|
|
924
|
+
addOps(39 /* LispType.Try */, ({ exec, done, ticks, a, b, context, scope, inLoopOrSwitch }) => {
|
|
925
|
+
const [exception, catchBody, finallyBody] = b;
|
|
926
|
+
// Execute try block
|
|
927
|
+
executeTreeWithDone(exec, (...tryArgs) => {
|
|
928
|
+
const tryHadError = tryArgs.length === 1;
|
|
929
|
+
const tryError = tryHadError ? tryArgs[0] : undefined;
|
|
930
|
+
const tryResult = !tryHadError && tryArgs.length > 1 ? tryArgs[1] : undefined;
|
|
931
|
+
// Handler to execute finally and complete
|
|
932
|
+
const executeFinallyAndComplete = (hadError, errorOrResult) => {
|
|
933
|
+
if (finallyBody && finallyBody.length > 0) {
|
|
934
|
+
// Execute finally block
|
|
935
|
+
executeTreeWithDone(exec, (...finallyArgs) => {
|
|
936
|
+
const finallyHadError = finallyArgs.length === 1;
|
|
937
|
+
const finallyResult = !finallyHadError && finallyArgs.length > 1 ? finallyArgs[1] : undefined;
|
|
938
|
+
// If finally throws an error, it overrides everything
|
|
939
|
+
if (finallyHadError) {
|
|
940
|
+
done(finallyArgs[0]);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
// If finally has a control flow statement (return/break/continue), it overrides everything
|
|
944
|
+
if (finallyResult instanceof ExecReturn &&
|
|
945
|
+
(finallyResult.returned || finallyResult.breakLoop || finallyResult.continueLoop)) {
|
|
946
|
+
done(undefined, finallyResult);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
// Otherwise, return the original try/catch result/error
|
|
950
|
+
if (hadError) {
|
|
951
|
+
done(errorOrResult);
|
|
952
|
+
}
|
|
953
|
+
else if (errorOrResult instanceof ExecReturn) {
|
|
954
|
+
// If try/catch returned or has some other control flow, pass that through
|
|
955
|
+
if (errorOrResult.returned ||
|
|
956
|
+
errorOrResult.breakLoop ||
|
|
957
|
+
errorOrResult.continueLoop) {
|
|
958
|
+
done(undefined, errorOrResult);
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
// Normal completion - don't return a value
|
|
962
|
+
done();
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
// Try/catch completed normally, just signal completion with no return value
|
|
967
|
+
done();
|
|
968
|
+
}
|
|
969
|
+
}, ticks, context, finallyBody, [new utils.Scope(scope, {})], inLoopOrSwitch);
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
// No finally block, just return result/error
|
|
973
|
+
if (hadError) {
|
|
974
|
+
done(errorOrResult);
|
|
975
|
+
}
|
|
976
|
+
else if (errorOrResult instanceof ExecReturn) {
|
|
977
|
+
// If try/catch returned or has some other control flow, pass that through
|
|
978
|
+
if (errorOrResult.returned || errorOrResult.breakLoop || errorOrResult.continueLoop) {
|
|
979
|
+
done(undefined, errorOrResult);
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
// Normal completion - don't return a value
|
|
983
|
+
done();
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
done();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
// If try had an error and there's a catch block, execute catch
|
|
992
|
+
if (tryHadError && catchBody && catchBody.length > 0) {
|
|
993
|
+
const sc = {};
|
|
994
|
+
if (exception)
|
|
995
|
+
sc[exception] = tryError;
|
|
996
|
+
executeTreeWithDone(exec, (...catchArgs) => {
|
|
997
|
+
const catchHadError = catchArgs.length === 1;
|
|
998
|
+
const catchErrorOrResult = catchHadError
|
|
999
|
+
? catchArgs[0]
|
|
1000
|
+
: catchArgs.length > 1
|
|
1001
|
+
? catchArgs[1]
|
|
1002
|
+
: undefined;
|
|
1003
|
+
// Execute finally with catch result
|
|
1004
|
+
executeFinallyAndComplete(catchHadError, catchErrorOrResult);
|
|
1005
|
+
}, ticks, context, catchBody, [new utils.Scope(scope, sc)], inLoopOrSwitch);
|
|
1006
|
+
}
|
|
1007
|
+
else {
|
|
1008
|
+
// No catch or no error, execute finally with try result
|
|
1009
|
+
executeFinallyAndComplete(tryHadError, tryHadError ? tryError : tryResult);
|
|
1010
|
+
}
|
|
1011
|
+
}, ticks, context, a, [new utils.Scope(scope)], inLoopOrSwitch);
|
|
1012
|
+
});
|
|
1013
|
+
addOps(87 /* LispType.Void */, ({ done }) => {
|
|
1014
|
+
done();
|
|
1015
|
+
});
|
|
1016
|
+
addOps(45 /* LispType.New */, ({ done, a, b, context }) => {
|
|
1017
|
+
if (!context.ctx.globalsWhitelist.has(a) && !context.ctx.sandboxedFunctions.has(a)) {
|
|
1018
|
+
throw new utils.SandboxAccessError(`Object construction not allowed: ${a.constructor.name}`);
|
|
1019
|
+
}
|
|
1020
|
+
done(undefined, new a(...b));
|
|
1021
|
+
});
|
|
1022
|
+
addOps(46 /* LispType.Throw */, ({ done, b }) => {
|
|
1023
|
+
done(b);
|
|
1024
|
+
});
|
|
1025
|
+
addOps(43 /* LispType.Expression */, ({ done, a }) => done(undefined, a.pop()));
|
|
1026
|
+
addOps(0 /* LispType.None */, ({ done }) => done());
|
|
1027
|
+
function valueOrProp(a, context) {
|
|
1028
|
+
if (a instanceof utils.Prop)
|
|
1029
|
+
return a.get(context);
|
|
1030
|
+
if (a === optional)
|
|
1031
|
+
return undefined;
|
|
1032
|
+
return a;
|
|
1033
|
+
}
|
|
1034
|
+
function execMany(ticks, exec, tree, done, scope, context, inLoopOrSwitch) {
|
|
1035
|
+
if (exec === execSync) {
|
|
1036
|
+
_execManySync(ticks, tree, done, scope, context, inLoopOrSwitch);
|
|
1037
|
+
}
|
|
1038
|
+
else {
|
|
1039
|
+
_execManyAsync(ticks, tree, done, scope, context, inLoopOrSwitch).catch(done);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
function _execManySync(ticks, tree, done, scope, context, inLoopOrSwitch) {
|
|
1043
|
+
const ret = [];
|
|
1044
|
+
for (let i = 0; i < tree.length; i++) {
|
|
1045
|
+
let res = syncDone((d) => execSync(ticks, tree[i], scope, context, d, inLoopOrSwitch)).result;
|
|
1046
|
+
if (res instanceof ExecReturn && (res.returned || res.breakLoop || res.continueLoop)) {
|
|
1047
|
+
done(undefined, res);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
if (utils.isLisp(tree[i]) && tree[i][0] === 8 /* LispType.Return */) {
|
|
1051
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, res, true));
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
ret.push(res);
|
|
1055
|
+
}
|
|
1056
|
+
done(undefined, ret);
|
|
1057
|
+
}
|
|
1058
|
+
async function _execManyAsync(ticks, tree, done, scope, context, inLoopOrSwitch) {
|
|
1059
|
+
const ret = [];
|
|
1060
|
+
for (let i = 0; i < tree.length; i++) {
|
|
1061
|
+
let res;
|
|
1062
|
+
try {
|
|
1063
|
+
let ad;
|
|
1064
|
+
res =
|
|
1065
|
+
(ad = asyncDone((d) => execAsync(ticks, tree[i], scope, context, d, inLoopOrSwitch)))
|
|
1066
|
+
.isInstant === true
|
|
1067
|
+
? ad.instant
|
|
1068
|
+
: (await ad.p).result;
|
|
1069
|
+
}
|
|
1070
|
+
catch (e) {
|
|
1071
|
+
done(e);
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (res instanceof ExecReturn && (res.returned || res.breakLoop || res.continueLoop)) {
|
|
1075
|
+
done(undefined, res);
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
if (utils.isLisp(tree[i]) && tree[i][0] === 8 /* LispType.Return */) {
|
|
1079
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, res, true));
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
ret.push(res);
|
|
1083
|
+
}
|
|
1084
|
+
done(undefined, ret);
|
|
1085
|
+
}
|
|
1086
|
+
function asyncDone(callback) {
|
|
1087
|
+
let isInstant = false;
|
|
1088
|
+
let instant;
|
|
1089
|
+
const p = new Promise((resolve, reject) => {
|
|
1090
|
+
callback((...args) => {
|
|
1091
|
+
if (args.length === 1)
|
|
1092
|
+
reject(args[0]);
|
|
1093
|
+
else {
|
|
1094
|
+
isInstant = true;
|
|
1095
|
+
instant = args[1];
|
|
1096
|
+
resolve({ result: args[1] });
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
});
|
|
1100
|
+
return {
|
|
1101
|
+
isInstant,
|
|
1102
|
+
instant,
|
|
1103
|
+
p,
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function syncDone(callback) {
|
|
1107
|
+
let result;
|
|
1108
|
+
let err;
|
|
1109
|
+
callback((...args) => {
|
|
1110
|
+
err = args.length === 1 ? { error: args[0] } : undefined;
|
|
1111
|
+
result = args[1];
|
|
1112
|
+
});
|
|
1113
|
+
if (err)
|
|
1114
|
+
throw err.error;
|
|
1115
|
+
return { result };
|
|
1116
|
+
}
|
|
1117
|
+
async function execAsync(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
|
|
1118
|
+
let done = doneOriginal;
|
|
1119
|
+
const p = new Promise((resolve) => {
|
|
1120
|
+
done = (...args) => {
|
|
1121
|
+
doneOriginal(...args);
|
|
1122
|
+
resolve();
|
|
1123
|
+
};
|
|
1124
|
+
});
|
|
1125
|
+
if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
|
|
1126
|
+
let op = tree[0];
|
|
1127
|
+
let obj;
|
|
1128
|
+
try {
|
|
1129
|
+
let ad;
|
|
1130
|
+
obj =
|
|
1131
|
+
(ad = asyncDone((d) => execAsync(ticks, tree[1], scope, context, d, inLoopOrSwitch)))
|
|
1132
|
+
.isInstant === true
|
|
1133
|
+
? ad.instant
|
|
1134
|
+
: (await ad.p).result;
|
|
1135
|
+
}
|
|
1136
|
+
catch (e) {
|
|
1137
|
+
done(e);
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
let a = obj;
|
|
1141
|
+
try {
|
|
1142
|
+
a = obj instanceof utils.Prop ? obj.get(context) : obj;
|
|
1143
|
+
}
|
|
1144
|
+
catch (e) {
|
|
1145
|
+
done(e);
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
if (op === 20 /* LispType.PropOptional */ || op === 21 /* LispType.CallOptional */) {
|
|
1149
|
+
if (a === undefined || a === null) {
|
|
1150
|
+
done(undefined, optional);
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
op = op === 20 /* LispType.PropOptional */ ? 1 /* LispType.Prop */ : 5 /* LispType.Call */;
|
|
1154
|
+
}
|
|
1155
|
+
if (a === optional) {
|
|
1156
|
+
if (op === 1 /* LispType.Prop */ || op === 5 /* LispType.Call */) {
|
|
1157
|
+
done(undefined, a);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
a = undefined;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
// Short-circuit for nullish coalescing: if a is not null/undefined, return a without evaluating b
|
|
1165
|
+
if (op === 89 /* LispType.NullishCoalescing */ && a !== undefined && a !== null) {
|
|
1166
|
+
done(undefined, a);
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
let bobj;
|
|
1170
|
+
try {
|
|
1171
|
+
let ad;
|
|
1172
|
+
bobj =
|
|
1173
|
+
(ad = asyncDone((d) => execAsync(ticks, tree[2], scope, context, d, inLoopOrSwitch)))
|
|
1174
|
+
.isInstant === true
|
|
1175
|
+
? ad.instant
|
|
1176
|
+
: (await ad.p).result;
|
|
1177
|
+
}
|
|
1178
|
+
catch (e) {
|
|
1179
|
+
done(e);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
let b = bobj;
|
|
1183
|
+
try {
|
|
1184
|
+
b = bobj instanceof utils.Prop ? bobj.get(context) : bobj;
|
|
1185
|
+
}
|
|
1186
|
+
catch (e) {
|
|
1187
|
+
done(e);
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
if (b === optional) {
|
|
1191
|
+
b = undefined;
|
|
1192
|
+
}
|
|
1193
|
+
performOp({
|
|
1194
|
+
op,
|
|
1195
|
+
exec: execAsync,
|
|
1196
|
+
done,
|
|
1197
|
+
ticks,
|
|
1198
|
+
a,
|
|
1199
|
+
b,
|
|
1200
|
+
obj,
|
|
1201
|
+
context,
|
|
1202
|
+
scope,
|
|
1203
|
+
bobj,
|
|
1204
|
+
inLoopOrSwitch,
|
|
1205
|
+
tree,
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
await p;
|
|
1209
|
+
}
|
|
1210
|
+
function execSync(ticks, tree, scope, context, done, inLoopOrSwitch) {
|
|
1211
|
+
if (!_execNoneRecurse(ticks, tree, scope, context, done, false, inLoopOrSwitch) && utils.isLisp(tree)) {
|
|
1212
|
+
let op = tree[0];
|
|
1213
|
+
let obj = syncDone((d) => execSync(ticks, tree[1], scope, context, d, inLoopOrSwitch)).result;
|
|
1214
|
+
let a = obj instanceof utils.Prop ? obj.get(context) : obj;
|
|
1215
|
+
if (op === 20 /* LispType.PropOptional */ || op === 21 /* LispType.CallOptional */) {
|
|
1216
|
+
if (a === undefined || a === null) {
|
|
1217
|
+
done(undefined, optional);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
op = op === 20 /* LispType.PropOptional */ ? 1 /* LispType.Prop */ : 5 /* LispType.Call */;
|
|
1221
|
+
}
|
|
1222
|
+
if (a === optional) {
|
|
1223
|
+
if (op === 1 /* LispType.Prop */ || op === 5 /* LispType.Call */) {
|
|
1224
|
+
done(undefined, a);
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
a = undefined;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
// Short-circuit for nullish coalescing: if a is not null/undefined, return a without evaluating b
|
|
1232
|
+
if (op === 89 /* LispType.NullishCoalescing */ && a !== undefined && a !== null) {
|
|
1233
|
+
done(undefined, a);
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
let bobj = syncDone((d) => execSync(ticks, tree[2], scope, context, d, inLoopOrSwitch)).result;
|
|
1237
|
+
let b = bobj instanceof utils.Prop ? bobj.get(context) : bobj;
|
|
1238
|
+
if (b === optional) {
|
|
1239
|
+
b = undefined;
|
|
1240
|
+
}
|
|
1241
|
+
performOp({
|
|
1242
|
+
op,
|
|
1243
|
+
exec: execSync,
|
|
1244
|
+
done,
|
|
1245
|
+
ticks,
|
|
1246
|
+
a,
|
|
1247
|
+
b,
|
|
1248
|
+
obj,
|
|
1249
|
+
context,
|
|
1250
|
+
scope,
|
|
1251
|
+
bobj,
|
|
1252
|
+
inLoopOrSwitch,
|
|
1253
|
+
tree,
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function checkHaltExpectedTicks(params, expectTicks = 0) {
|
|
1258
|
+
const sandbox = params.context.ctx.sandbox;
|
|
1259
|
+
const options = params.context.ctx.options;
|
|
1260
|
+
const { ticks, scope, context, done, op } = params;
|
|
1261
|
+
if (sandbox.halted) {
|
|
1262
|
+
const sub = sandbox.subscribeResume(() => {
|
|
1263
|
+
sub.unsubscribe();
|
|
1264
|
+
try {
|
|
1265
|
+
const o = ops.get(op);
|
|
1266
|
+
if (!o) {
|
|
1267
|
+
done(new SyntaxError('Unknown operator: ' + op));
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
o(params);
|
|
1271
|
+
}
|
|
1272
|
+
catch (err) {
|
|
1273
|
+
if (options.haltOnSandboxError && err instanceof utils.SandboxError) {
|
|
1274
|
+
const sub = sandbox.subscribeResume(() => {
|
|
1275
|
+
sub.unsubscribe();
|
|
1276
|
+
done(err);
|
|
1277
|
+
});
|
|
1278
|
+
sandbox.haltExecution({
|
|
1279
|
+
error: err,
|
|
1280
|
+
ticks,
|
|
1281
|
+
scope,
|
|
1282
|
+
context,
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
else {
|
|
1286
|
+
done(err);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
return true;
|
|
1291
|
+
}
|
|
1292
|
+
else if (ticks.tickLimit && ticks.tickLimit <= ticks.ticks + BigInt(expectTicks)) {
|
|
1293
|
+
const sub = sandbox.subscribeResume(() => {
|
|
1294
|
+
sub.unsubscribe();
|
|
1295
|
+
try {
|
|
1296
|
+
const o = ops.get(op);
|
|
1297
|
+
if (!o) {
|
|
1298
|
+
done(new SyntaxError('Unknown operator: ' + op));
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
o(params);
|
|
1302
|
+
}
|
|
1303
|
+
catch (err) {
|
|
1304
|
+
if (context.ctx.options.haltOnSandboxError && err instanceof utils.SandboxError) {
|
|
1305
|
+
const sub = sandbox.subscribeResume(() => {
|
|
1306
|
+
sub.unsubscribe();
|
|
1307
|
+
done(err);
|
|
1308
|
+
});
|
|
1309
|
+
sandbox.haltExecution({
|
|
1310
|
+
error: err,
|
|
1311
|
+
ticks,
|
|
1312
|
+
scope,
|
|
1313
|
+
context,
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
done(err);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
const error = new utils.SandboxExecutionQuotaExceededError('Execution quota exceeded');
|
|
1322
|
+
sandbox.haltExecution({
|
|
1323
|
+
error,
|
|
1324
|
+
ticks,
|
|
1325
|
+
scope: scope,
|
|
1326
|
+
context,
|
|
1327
|
+
});
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
return false;
|
|
1331
|
+
}
|
|
1332
|
+
function performOp(params) {
|
|
1333
|
+
const { done, op, ticks, context, scope } = params;
|
|
1334
|
+
ticks.ticks++;
|
|
1335
|
+
const sandbox = context.ctx.sandbox;
|
|
1336
|
+
if (checkHaltExpectedTicks(params)) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
try {
|
|
1340
|
+
const o = ops.get(op);
|
|
1341
|
+
if (!o) {
|
|
1342
|
+
done(new utils.SandboxExecutionTreeError('Unknown operator: ' + op));
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
o(params);
|
|
1346
|
+
}
|
|
1347
|
+
catch (err) {
|
|
1348
|
+
if (context.ctx.options.haltOnSandboxError && err instanceof utils.SandboxError) {
|
|
1349
|
+
const sub = sandbox.subscribeResume(() => {
|
|
1350
|
+
sub.unsubscribe();
|
|
1351
|
+
done(err);
|
|
1352
|
+
});
|
|
1353
|
+
sandbox.haltExecution({
|
|
1354
|
+
error: err,
|
|
1355
|
+
ticks,
|
|
1356
|
+
scope,
|
|
1357
|
+
context,
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
else {
|
|
1361
|
+
done(err);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
const unexecTypes = new Set([
|
|
1366
|
+
11 /* LispType.ArrowFunction */,
|
|
1367
|
+
37 /* LispType.Function */,
|
|
1368
|
+
10 /* LispType.InlineFunction */,
|
|
1369
|
+
38 /* LispType.Loop */,
|
|
1370
|
+
39 /* LispType.Try */,
|
|
1371
|
+
40 /* LispType.Switch */,
|
|
1372
|
+
14 /* LispType.IfCase */,
|
|
1373
|
+
16 /* LispType.InlineIfCase */,
|
|
1374
|
+
60 /* LispType.Typeof */,
|
|
1375
|
+
]);
|
|
1376
|
+
function _execNoneRecurse(ticks, tree, scope, context, done, isAsync, inLoopOrSwitch) {
|
|
1377
|
+
const exec = isAsync ? execAsync : execSync;
|
|
1378
|
+
if (tree instanceof utils.Prop) {
|
|
1379
|
+
done(undefined, tree.get(context));
|
|
1380
|
+
}
|
|
1381
|
+
else if (tree === optional) {
|
|
1382
|
+
done();
|
|
1383
|
+
}
|
|
1384
|
+
else if (Array.isArray(tree) && !utils.isLisp(tree)) {
|
|
1385
|
+
if (tree[0] === 0 /* LispType.None */) {
|
|
1386
|
+
done();
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
execMany(ticks, exec, tree, done, scope, context, inLoopOrSwitch);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
else if (!utils.isLisp(tree)) {
|
|
1393
|
+
done(undefined, tree);
|
|
1394
|
+
}
|
|
1395
|
+
else if (tree[0] === 42 /* LispType.Block */) {
|
|
1396
|
+
execMany(ticks, exec, tree[1], done, scope, context, inLoopOrSwitch);
|
|
1397
|
+
}
|
|
1398
|
+
else if (tree[0] === 44 /* LispType.Await */) {
|
|
1399
|
+
if (!isAsync) {
|
|
1400
|
+
done(new SyntaxError("Illegal use of 'await', must be inside async function"));
|
|
1401
|
+
}
|
|
1402
|
+
else if (context.ctx.prototypeWhitelist?.has(Promise.prototype)) {
|
|
1403
|
+
execAsync(ticks, tree[1], scope, context, async (...args) => {
|
|
1404
|
+
if (args.length === 1)
|
|
1405
|
+
done(args[0]);
|
|
1406
|
+
else
|
|
1407
|
+
try {
|
|
1408
|
+
done(undefined, (await valueOrProp(args[1], context)));
|
|
1409
|
+
}
|
|
1410
|
+
catch (err) {
|
|
1411
|
+
done(err);
|
|
1412
|
+
}
|
|
1413
|
+
}, inLoopOrSwitch).catch(done);
|
|
1414
|
+
}
|
|
1415
|
+
else {
|
|
1416
|
+
done(new utils.SandboxCapabilityError('Async/await is not permitted'));
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
else if (unexecTypes.has(tree[0])) {
|
|
1420
|
+
performOp({
|
|
1421
|
+
op: tree[0],
|
|
1422
|
+
exec,
|
|
1423
|
+
done,
|
|
1424
|
+
ticks,
|
|
1425
|
+
a: tree[1],
|
|
1426
|
+
b: tree[2],
|
|
1427
|
+
obj: tree,
|
|
1428
|
+
tree,
|
|
1429
|
+
context,
|
|
1430
|
+
scope,
|
|
1431
|
+
bobj: undefined,
|
|
1432
|
+
inLoopOrSwitch,
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
else {
|
|
1436
|
+
return false;
|
|
1437
|
+
}
|
|
1438
|
+
return true;
|
|
1439
|
+
}
|
|
1440
|
+
function executeTree(ticks, context, executionTree, scopes = [], inLoopOrSwitch) {
|
|
1441
|
+
return syncDone((done) => executeTreeWithDone(execSync, done, ticks, context, executionTree, scopes, inLoopOrSwitch)).result;
|
|
1442
|
+
}
|
|
1443
|
+
async function executeTreeAsync(ticks, context, executionTree, scopes = [], inLoopOrSwitch) {
|
|
1444
|
+
let ad;
|
|
1445
|
+
return (ad = asyncDone((done) => executeTreeWithDone(execAsync, done, ticks, context, executionTree, scopes, inLoopOrSwitch))).isInstant === true
|
|
1446
|
+
? ad.instant
|
|
1447
|
+
: (await ad.p).result;
|
|
1448
|
+
}
|
|
1449
|
+
function executeTreeWithDone(exec, done, ticks, context, executionTree, scopes = [], inLoopOrSwitch) {
|
|
1450
|
+
if (!executionTree) {
|
|
1451
|
+
done();
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
if (!(executionTree instanceof Array)) {
|
|
1455
|
+
throw new SyntaxError('Bad execution tree');
|
|
1456
|
+
}
|
|
1457
|
+
let scope = context.ctx.globalScope;
|
|
1458
|
+
let s;
|
|
1459
|
+
while ((s = scopes.shift())) {
|
|
1460
|
+
if (typeof s !== 'object')
|
|
1461
|
+
continue;
|
|
1462
|
+
if (s instanceof utils.Scope) {
|
|
1463
|
+
scope = s;
|
|
1464
|
+
}
|
|
1465
|
+
else {
|
|
1466
|
+
scope = new utils.Scope(scope, s, s instanceof utils.LocalScope ? undefined : null);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
if (context.ctx.options.audit && !context.ctx.auditReport) {
|
|
1470
|
+
context.ctx.auditReport = {
|
|
1471
|
+
globalsAccess: new Set(),
|
|
1472
|
+
prototypeAccess: {},
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
if (exec === execSync) {
|
|
1476
|
+
_executeWithDoneSync(done, ticks, context, executionTree, scope, inLoopOrSwitch);
|
|
1477
|
+
}
|
|
1478
|
+
else {
|
|
1479
|
+
_executeWithDoneAsync(done, ticks, context, executionTree, scope, inLoopOrSwitch).catch(done);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
function _executeWithDoneSync(done, ticks, context, executionTree, scope, inLoopOrSwitch) {
|
|
1483
|
+
if (!(executionTree instanceof Array))
|
|
1484
|
+
throw new SyntaxError('Bad execution tree');
|
|
1485
|
+
let i = 0;
|
|
1486
|
+
for (i = 0; i < executionTree.length; i++) {
|
|
1487
|
+
let res;
|
|
1488
|
+
let err;
|
|
1489
|
+
const current = executionTree[i];
|
|
1490
|
+
try {
|
|
1491
|
+
execSync(ticks, current, scope, context, (...args) => {
|
|
1492
|
+
if (args.length === 1)
|
|
1493
|
+
err = { error: args[0] };
|
|
1494
|
+
else
|
|
1495
|
+
res = args[1];
|
|
1496
|
+
}, inLoopOrSwitch);
|
|
1497
|
+
}
|
|
1498
|
+
catch (e) {
|
|
1499
|
+
err = { error: e };
|
|
1500
|
+
}
|
|
1501
|
+
if (err) {
|
|
1502
|
+
done(err.error);
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
if (res instanceof ExecReturn) {
|
|
1506
|
+
done(undefined, res);
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
if (utils.isLisp(current) && current[0] === 8 /* LispType.Return */) {
|
|
1510
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, res, true));
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, undefined, false));
|
|
1515
|
+
}
|
|
1516
|
+
async function _executeWithDoneAsync(done, ticks, context, executionTree, scope, inLoopOrSwitch) {
|
|
1517
|
+
if (!(executionTree instanceof Array))
|
|
1518
|
+
throw new SyntaxError('Bad execution tree');
|
|
1519
|
+
let i = 0;
|
|
1520
|
+
for (i = 0; i < executionTree.length; i++) {
|
|
1521
|
+
let res;
|
|
1522
|
+
let err;
|
|
1523
|
+
const current = executionTree[i];
|
|
1524
|
+
try {
|
|
1525
|
+
await execAsync(ticks, current, scope, context, (...args) => {
|
|
1526
|
+
if (args.length === 1)
|
|
1527
|
+
err = { error: args[0] };
|
|
1528
|
+
else
|
|
1529
|
+
res = args[1];
|
|
1530
|
+
}, inLoopOrSwitch);
|
|
1531
|
+
}
|
|
1532
|
+
catch (e) {
|
|
1533
|
+
err = { error: e };
|
|
1534
|
+
}
|
|
1535
|
+
if (err) {
|
|
1536
|
+
done(err.error);
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
if (res instanceof ExecReturn) {
|
|
1540
|
+
done(undefined, res);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
if (utils.isLisp(current) && current[0] === 8 /* LispType.Return */) {
|
|
1544
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, res, true));
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
done(undefined, new ExecReturn(context.ctx.auditReport, undefined, false));
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
exports.ExecReturn = ExecReturn;
|
|
1552
|
+
exports.If = If;
|
|
1553
|
+
exports.KeyVal = KeyVal;
|
|
1554
|
+
exports.SpreadArray = SpreadArray;
|
|
1555
|
+
exports.SpreadObject = SpreadObject;
|
|
1556
|
+
exports.addOps = addOps;
|
|
1557
|
+
exports.assignCheck = assignCheck;
|
|
1558
|
+
exports.asyncDone = asyncDone;
|
|
1559
|
+
exports.createFunction = createFunction;
|
|
1560
|
+
exports.createFunctionAsync = createFunctionAsync;
|
|
1561
|
+
exports.execAsync = execAsync;
|
|
1562
|
+
exports.execMany = execMany;
|
|
1563
|
+
exports.execSync = execSync;
|
|
1564
|
+
exports.executeTree = executeTree;
|
|
1565
|
+
exports.executeTreeAsync = executeTreeAsync;
|
|
1566
|
+
exports.ops = ops;
|
|
1567
|
+
exports.syncDone = syncDone;
|