@squiz/render-runtime-lib 1.2.1-alpha.100
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/README.md +11 -0
- package/lib/component-runner/component-runner.spec.d.ts +1 -0
- package/lib/component-runner/index.d.ts +22 -0
- package/lib/component-runner/worker/WorkerPool.d.ts +50 -0
- package/lib/component-runner/worker/getRuntimeModules.d.ts +1 -0
- package/lib/component-runner/worker/worker-root.d.ts +1 -0
- package/lib/index.d.ts +25 -0
- package/lib/index.js +112791 -0
- package/lib/index.js.map +7 -0
- package/lib/migrations/20220704054051_initial.sql +19 -0
- package/lib/migrations/20220718172237_adding_component_sets.sql +23 -0
- package/lib/migrations/20220728113941_add_env_vars_field.sql +1 -0
- package/lib/migrations/20220817113300_removing_null_props_from_jsonb.sql +41 -0
- package/lib/render-runtime-lib.spec.d.ts +1 -0
- package/lib/test/helpers/fixtures.d.ts +20 -0
- package/lib/test/helpers/stack.d.ts +6 -0
- package/lib/test/index.d.ts +2 -0
- package/lib/utils/convertFunctionStaticFilesToFqdn.d.ts +1 -0
- package/lib/utils/convertFunctionStaticFilesToFqdn.spec.d.ts +1 -0
- package/lib/utils/getFunctionDefinitionFromManifest.d.ts +2 -0
- package/lib/utils/getManifestPath.d.ts +1 -0
- package/lib/utils/getManifestPath.spec.d.ts +1 -0
- package/lib/utils/getPreviewFilePath.d.ts +1 -0
- package/lib/utils/getPreviewFilePath.spec.d.ts +1 -0
- package/lib/utils/isInProductionMode.d.ts +1 -0
- package/lib/utils/isInProductionMode.spec.d.ts +1 -0
- package/lib/utils/resolvePreviewOutput.d.ts +2 -0
- package/lib/utils/resolvePreviewOutput.spec.d.ts +1 -0
- package/lib/webserver/app.d.ts +4 -0
- package/lib/webserver/controllers/core.d.ts +3 -0
- package/lib/webserver/controllers/core.spec.d.ts +1 -0
- package/lib/webserver/controllers/definition.d.ts +3 -0
- package/lib/webserver/controllers/definition.spec.d.ts +1 -0
- package/lib/webserver/controllers/index.d.ts +4 -0
- package/lib/webserver/controllers/render.d.ts +3 -0
- package/lib/webserver/controllers/render.spec.d.ts +1 -0
- package/lib/webserver/controllers/static.d.ts +3 -0
- package/lib/webserver/controllers/static.spec.d.ts +1 -0
- package/lib/webserver/controllers/test/definition-route-tests.d.ts +1 -0
- package/lib/webserver/controllers/test/render-route-tests.d.ts +1 -0
- package/lib/webserver/controllers/test/static-route-tests.d.ts +1 -0
- package/lib/webserver/index.d.ts +22 -0
- package/lib/worker/bridge.js +1010 -0
- package/lib/worker/compiler.js +87 -0
- package/lib/worker/events.js +977 -0
- package/lib/worker/nodevm.js +503 -0
- package/lib/worker/resolver-compat.js +342 -0
- package/lib/worker/resolver.js +882 -0
- package/lib/worker/script.js +388 -0
- package/lib/worker/setup-node-sandbox.js +469 -0
- package/lib/worker/setup-sandbox.js +456 -0
- package/lib/worker/transformer.js +180 -0
- package/lib/worker/vm.js +539 -0
- package/lib/worker/worker-root.js +41743 -0
- package/lib/worker/worker-root.js.map +7 -0
- package/package.json +60 -0
package/lib/worker/vm.js
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This callback will be called to transform a script to JavaScript.
|
|
5
|
+
*
|
|
6
|
+
* @callback compileCallback
|
|
7
|
+
* @param {string} code - Script code to transform to JavaScript.
|
|
8
|
+
* @param {string} filename - Filename of this script.
|
|
9
|
+
* @return {string} JavaScript code that represents the script code.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* This callback will be called to resolve a module if it couldn't be found.
|
|
14
|
+
*
|
|
15
|
+
* @callback resolveCallback
|
|
16
|
+
* @param {string} moduleName - Name of the modulusedRequiree to resolve.
|
|
17
|
+
* @param {string} dirname - Name of the current directory.
|
|
18
|
+
* @return {(string|undefined)} The file or directory to use to load the requested module.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const pa = require('path');
|
|
23
|
+
const {
|
|
24
|
+
Script,
|
|
25
|
+
createContext
|
|
26
|
+
} = require('vm');
|
|
27
|
+
const {
|
|
28
|
+
EventEmitter
|
|
29
|
+
} = require('events');
|
|
30
|
+
const {
|
|
31
|
+
INSPECT_MAX_BYTES
|
|
32
|
+
} = require('buffer');
|
|
33
|
+
const {
|
|
34
|
+
createBridge,
|
|
35
|
+
VMError
|
|
36
|
+
} = require('./bridge');
|
|
37
|
+
const {
|
|
38
|
+
transformer,
|
|
39
|
+
INTERNAL_STATE_NAME
|
|
40
|
+
} = require('./transformer');
|
|
41
|
+
const {
|
|
42
|
+
lookupCompiler
|
|
43
|
+
} = require('./compiler');
|
|
44
|
+
const {
|
|
45
|
+
VMScript
|
|
46
|
+
} = require('./script');
|
|
47
|
+
|
|
48
|
+
const objectDefineProperties = Object.defineProperties;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Host objects
|
|
52
|
+
*
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
const HOST = Object.freeze({
|
|
56
|
+
Buffer,
|
|
57
|
+
Function,
|
|
58
|
+
Object,
|
|
59
|
+
transformAndCheck,
|
|
60
|
+
INSPECT_MAX_BYTES,
|
|
61
|
+
INTERNAL_STATE_NAME
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Compile a script.
|
|
66
|
+
*
|
|
67
|
+
* @private
|
|
68
|
+
* @param {string} filename - Filename of the script.
|
|
69
|
+
* @param {string} script - Script.
|
|
70
|
+
* @return {vm.Script} The compiled script.
|
|
71
|
+
*/
|
|
72
|
+
function compileScript(filename, script) {
|
|
73
|
+
return new Script(script, {
|
|
74
|
+
__proto__: null,
|
|
75
|
+
filename,
|
|
76
|
+
displayErrors: false
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Default run options for vm.Script.runInContext
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
const DEFAULT_RUN_OPTIONS = Object.freeze({__proto__: null, displayErrors: false});
|
|
86
|
+
|
|
87
|
+
function checkAsync(allow) {
|
|
88
|
+
if (!allow) throw new VMError('Async not available');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function transformAndCheck(args, code, isAsync, isGenerator, allowAsync) {
|
|
92
|
+
const ret = transformer(args, code, isAsync, isGenerator, undefined);
|
|
93
|
+
checkAsync(allowAsync || !ret.hasAsync);
|
|
94
|
+
return ret.code;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
*
|
|
99
|
+
* This callback will be called and has a specific time to finish.<br>
|
|
100
|
+
* No parameters will be supplied.<br>
|
|
101
|
+
* If parameters are required, use a closure.
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
* @callback runWithTimeout
|
|
105
|
+
* @return {*}
|
|
106
|
+
*
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
let cacheTimeoutContext = null;
|
|
110
|
+
let cacheTimeoutScript = null;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Run a function with a specific timeout.
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
* @param {runWithTimeout} fn - Function to run with the specific timeout.
|
|
117
|
+
* @param {number} timeout - The amount of time to give the function to finish.
|
|
118
|
+
* @return {*} The value returned by the function.
|
|
119
|
+
* @throws {Error} If the function took to long.
|
|
120
|
+
*/
|
|
121
|
+
function doWithTimeout(fn, timeout) {
|
|
122
|
+
if (!cacheTimeoutContext) {
|
|
123
|
+
cacheTimeoutContext = createContext();
|
|
124
|
+
cacheTimeoutScript = new Script('fn()', {
|
|
125
|
+
__proto__: null,
|
|
126
|
+
filename: 'timeout_bridge.js',
|
|
127
|
+
displayErrors: false
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
cacheTimeoutContext.fn = fn;
|
|
131
|
+
try {
|
|
132
|
+
return cacheTimeoutScript.runInContext(cacheTimeoutContext, {
|
|
133
|
+
__proto__: null,
|
|
134
|
+
displayErrors: false,
|
|
135
|
+
timeout
|
|
136
|
+
});
|
|
137
|
+
} finally {
|
|
138
|
+
cacheTimeoutContext.fn = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const bridgeScript = compileScript(`${__dirname}/bridge.js`,
|
|
143
|
+
`(function(global) {"use strict"; const exports = {};${fs.readFileSync(`${__dirname}/bridge.js`, 'utf8')}\nreturn exports;})`);
|
|
144
|
+
const setupSandboxScript = compileScript(`${__dirname}/setup-sandbox.js`,
|
|
145
|
+
`(function(global, host, bridge, data, context) { ${fs.readFileSync(`${__dirname}/setup-sandbox.js`, 'utf8')}\n})`);
|
|
146
|
+
const getGlobalScript = compileScript('get_global.js', 'this');
|
|
147
|
+
|
|
148
|
+
let getGeneratorFunctionScript = null;
|
|
149
|
+
let getAsyncFunctionScript = null;
|
|
150
|
+
let getAsyncGeneratorFunctionScript = null;
|
|
151
|
+
try {
|
|
152
|
+
getGeneratorFunctionScript = compileScript('get_generator_function.js', '(function*(){}).constructor');
|
|
153
|
+
} catch (ex) {}
|
|
154
|
+
try {
|
|
155
|
+
getAsyncFunctionScript = compileScript('get_async_function.js', '(async function(){}).constructor');
|
|
156
|
+
} catch (ex) {}
|
|
157
|
+
try {
|
|
158
|
+
getAsyncGeneratorFunctionScript = compileScript('get_async_generator_function.js', '(async function*(){}).constructor');
|
|
159
|
+
} catch (ex) {}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Class VM.
|
|
163
|
+
*
|
|
164
|
+
* @public
|
|
165
|
+
*/
|
|
166
|
+
class VM extends EventEmitter {
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The timeout for {@link VM#run} calls.
|
|
170
|
+
*
|
|
171
|
+
* @public
|
|
172
|
+
* @since v3.9.0
|
|
173
|
+
* @member {number} timeout
|
|
174
|
+
* @memberOf VM#
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get the global sandbox object.
|
|
179
|
+
*
|
|
180
|
+
* @public
|
|
181
|
+
* @readonly
|
|
182
|
+
* @since v3.9.0
|
|
183
|
+
* @member {Object} sandbox
|
|
184
|
+
* @memberOf VM#
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The compiler to use to get the JavaScript code.
|
|
189
|
+
*
|
|
190
|
+
* @public
|
|
191
|
+
* @readonly
|
|
192
|
+
* @since v3.9.0
|
|
193
|
+
* @member {(string|compileCallback)} compiler
|
|
194
|
+
* @memberOf VM#
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The resolved compiler to use to get the JavaScript code.
|
|
199
|
+
*
|
|
200
|
+
* @private
|
|
201
|
+
* @readonly
|
|
202
|
+
* @member {compileCallback} _compiler
|
|
203
|
+
* @memberOf VM#
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Create a new VM instance.
|
|
208
|
+
*
|
|
209
|
+
* @public
|
|
210
|
+
* @param {Object} [options] - VM options.
|
|
211
|
+
* @param {number} [options.timeout] - The amount of time until a call to {@link VM#run} will timeout.
|
|
212
|
+
* @param {Object} [options.sandbox] - Objects that will be copied into the global object of the sandbox.
|
|
213
|
+
* @param {(string|compileCallback)} [options.compiler="javascript"] - The compiler to use.
|
|
214
|
+
* @param {boolean} [options.eval=true] - Allow the dynamic evaluation of code via eval(code) or Function(code)().<br>
|
|
215
|
+
* Only available for node v10+.
|
|
216
|
+
* @param {boolean} [options.wasm=true] - Allow to run wasm code.<br>
|
|
217
|
+
* Only available for node v10+.
|
|
218
|
+
* @param {boolean} [options.allowAsync=true] - Allows for async functions.
|
|
219
|
+
* @throws {VMError} If the compiler is unknown.
|
|
220
|
+
*/
|
|
221
|
+
constructor(options = {}) {
|
|
222
|
+
super();
|
|
223
|
+
|
|
224
|
+
// Read all options
|
|
225
|
+
const {
|
|
226
|
+
timeout,
|
|
227
|
+
sandbox,
|
|
228
|
+
compiler = 'javascript',
|
|
229
|
+
allowAsync: optAllowAsync = true
|
|
230
|
+
} = options;
|
|
231
|
+
const allowEval = options.eval !== false;
|
|
232
|
+
const allowWasm = options.wasm !== false;
|
|
233
|
+
const allowAsync = optAllowAsync && !options.fixAsync;
|
|
234
|
+
|
|
235
|
+
// Early error if sandbox is not an object.
|
|
236
|
+
if (sandbox && 'object' !== typeof sandbox) {
|
|
237
|
+
throw new VMError('Sandbox must be object.');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Early error if compiler can't be found.
|
|
241
|
+
const resolvedCompiler = lookupCompiler(compiler);
|
|
242
|
+
|
|
243
|
+
// Create a new context for this vm.
|
|
244
|
+
const _context = createContext(undefined, {
|
|
245
|
+
__proto__: null,
|
|
246
|
+
codeGeneration: {
|
|
247
|
+
__proto__: null,
|
|
248
|
+
strings: allowEval,
|
|
249
|
+
wasm: allowWasm
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const sandboxGlobal = getGlobalScript.runInContext(_context, DEFAULT_RUN_OPTIONS);
|
|
254
|
+
|
|
255
|
+
// Initialize the sandbox bridge
|
|
256
|
+
const {
|
|
257
|
+
createBridge: sandboxCreateBridge
|
|
258
|
+
} = bridgeScript.runInContext(_context, DEFAULT_RUN_OPTIONS)(sandboxGlobal);
|
|
259
|
+
|
|
260
|
+
// Initialize the bridge
|
|
261
|
+
const bridge = createBridge(sandboxCreateBridge, () => {});
|
|
262
|
+
|
|
263
|
+
const data = {
|
|
264
|
+
__proto__: null,
|
|
265
|
+
allowAsync
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
if (getGeneratorFunctionScript) {
|
|
269
|
+
data.GeneratorFunction = getGeneratorFunctionScript.runInContext(_context, DEFAULT_RUN_OPTIONS);
|
|
270
|
+
}
|
|
271
|
+
if (getAsyncFunctionScript) {
|
|
272
|
+
data.AsyncFunction = getAsyncFunctionScript.runInContext(_context, DEFAULT_RUN_OPTIONS);
|
|
273
|
+
}
|
|
274
|
+
if (getAsyncGeneratorFunctionScript) {
|
|
275
|
+
data.AsyncGeneratorFunction = getAsyncGeneratorFunctionScript.runInContext(_context, DEFAULT_RUN_OPTIONS);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Create the bridge between the host and the sandbox.
|
|
279
|
+
const internal = setupSandboxScript.runInContext(_context, DEFAULT_RUN_OPTIONS)(sandboxGlobal, HOST, bridge.other, data, _context);
|
|
280
|
+
|
|
281
|
+
const runScript = (script) => {
|
|
282
|
+
// This closure is intentional to hide _context and bridge since the allow to access the sandbox directly which is unsafe.
|
|
283
|
+
let ret;
|
|
284
|
+
try {
|
|
285
|
+
ret = script.runInContext(_context, DEFAULT_RUN_OPTIONS);
|
|
286
|
+
} catch (e) {
|
|
287
|
+
throw bridge.from(e);
|
|
288
|
+
}
|
|
289
|
+
return bridge.from(ret);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const makeReadonly = (value, mock) => {
|
|
293
|
+
try {
|
|
294
|
+
internal.readonly(value, mock);
|
|
295
|
+
} catch (e) {
|
|
296
|
+
throw bridge.from(e);
|
|
297
|
+
}
|
|
298
|
+
return value;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const makeProtected = (value) => {
|
|
302
|
+
const sandboxBridge = bridge.other;
|
|
303
|
+
try {
|
|
304
|
+
sandboxBridge.fromWithFactory(sandboxBridge.protectedFactory, value);
|
|
305
|
+
} catch (e) {
|
|
306
|
+
throw bridge.from(e);
|
|
307
|
+
}
|
|
308
|
+
return value;
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const addProtoMapping = (hostProto, sandboxProto) => {
|
|
312
|
+
const sandboxBridge = bridge.other;
|
|
313
|
+
let otherProto;
|
|
314
|
+
try {
|
|
315
|
+
otherProto = sandboxBridge.from(sandboxProto);
|
|
316
|
+
sandboxBridge.addProtoMapping(otherProto, hostProto);
|
|
317
|
+
} catch (e) {
|
|
318
|
+
throw bridge.from(e);
|
|
319
|
+
}
|
|
320
|
+
bridge.addProtoMapping(hostProto, otherProto);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const addProtoMappingFactory = (hostProto, sandboxProtoFactory) => {
|
|
324
|
+
const sandboxBridge = bridge.other;
|
|
325
|
+
const factory = () => {
|
|
326
|
+
const proto = sandboxProtoFactory(this);
|
|
327
|
+
bridge.addProtoMapping(hostProto, proto);
|
|
328
|
+
return proto;
|
|
329
|
+
};
|
|
330
|
+
try {
|
|
331
|
+
const otherProtoFactory = sandboxBridge.from(factory);
|
|
332
|
+
sandboxBridge.addProtoMappingFactory(otherProtoFactory, hostProto);
|
|
333
|
+
} catch (e) {
|
|
334
|
+
throw bridge.from(e);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// Define the properties of this object.
|
|
339
|
+
// Use Object.defineProperties here to be able to
|
|
340
|
+
// hide and set properties read-only.
|
|
341
|
+
objectDefineProperties(this, {
|
|
342
|
+
__proto__: null,
|
|
343
|
+
timeout: {
|
|
344
|
+
__proto__: null,
|
|
345
|
+
value: timeout,
|
|
346
|
+
writable: true,
|
|
347
|
+
enumerable: true
|
|
348
|
+
},
|
|
349
|
+
compiler: {
|
|
350
|
+
__proto__: null,
|
|
351
|
+
value: compiler,
|
|
352
|
+
enumerable: true
|
|
353
|
+
},
|
|
354
|
+
sandbox: {
|
|
355
|
+
__proto__: null,
|
|
356
|
+
value: bridge.from(sandboxGlobal),
|
|
357
|
+
enumerable: true
|
|
358
|
+
},
|
|
359
|
+
_runScript: {__proto__: null, value: runScript},
|
|
360
|
+
_makeReadonly: {__proto__: null, value: makeReadonly},
|
|
361
|
+
_makeProtected: {__proto__: null, value: makeProtected},
|
|
362
|
+
_addProtoMapping: {__proto__: null, value: addProtoMapping},
|
|
363
|
+
_addProtoMappingFactory: {__proto__: null, value: addProtoMappingFactory},
|
|
364
|
+
_compiler: {__proto__: null, value: resolvedCompiler},
|
|
365
|
+
_allowAsync: {__proto__: null, value: allowAsync}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// prepare global sandbox
|
|
369
|
+
if (sandbox) {
|
|
370
|
+
this.setGlobals(sandbox);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Adds all the values to the globals.
|
|
376
|
+
*
|
|
377
|
+
* @public
|
|
378
|
+
* @since v3.9.0
|
|
379
|
+
* @param {Object} values - All values that will be added to the globals.
|
|
380
|
+
* @return {this} This for chaining.
|
|
381
|
+
* @throws {*} If the setter of a global throws an exception it is propagated. And the remaining globals will not be written.
|
|
382
|
+
*/
|
|
383
|
+
setGlobals(values) {
|
|
384
|
+
for (const name in values) {
|
|
385
|
+
if (Object.prototype.hasOwnProperty.call(values, name)) {
|
|
386
|
+
this.sandbox[name] = values[name];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Set a global value.
|
|
394
|
+
*
|
|
395
|
+
* @public
|
|
396
|
+
* @since v3.9.0
|
|
397
|
+
* @param {string} name - The name of the global.
|
|
398
|
+
* @param {*} value - The value of the global.
|
|
399
|
+
* @return {this} This for chaining.
|
|
400
|
+
* @throws {*} If the setter of the global throws an exception it is propagated.
|
|
401
|
+
*/
|
|
402
|
+
setGlobal(name, value) {
|
|
403
|
+
this.sandbox[name] = value;
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Get a global value.
|
|
409
|
+
*
|
|
410
|
+
* @public
|
|
411
|
+
* @since v3.9.0
|
|
412
|
+
* @param {string} name - The name of the global.
|
|
413
|
+
* @return {*} The value of the global.
|
|
414
|
+
* @throws {*} If the getter of the global throws an exception it is propagated.
|
|
415
|
+
*/
|
|
416
|
+
getGlobal(name) {
|
|
417
|
+
return this.sandbox[name];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Freezes the object inside VM making it read-only. Not available for primitive values.
|
|
422
|
+
*
|
|
423
|
+
* @public
|
|
424
|
+
* @param {*} value - Object to freeze.
|
|
425
|
+
* @param {string} [globalName] - Whether to add the object to global.
|
|
426
|
+
* @return {*} Object to freeze.
|
|
427
|
+
* @throws {*} If the setter of the global throws an exception it is propagated.
|
|
428
|
+
*/
|
|
429
|
+
freeze(value, globalName) {
|
|
430
|
+
this.readonly(value);
|
|
431
|
+
if (globalName) this.sandbox[globalName] = value;
|
|
432
|
+
return value;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Freezes the object inside VM making it read-only. Not available for primitive values.
|
|
437
|
+
*
|
|
438
|
+
* @public
|
|
439
|
+
* @param {*} value - Object to freeze.
|
|
440
|
+
* @param {*} [mock] - When the object does not have a property the mock is used before prototype lookup.
|
|
441
|
+
* @return {*} Object to freeze.
|
|
442
|
+
*/
|
|
443
|
+
readonly(value, mock) {
|
|
444
|
+
return this._makeReadonly(value, mock);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Protects the object inside VM making impossible to set functions as it's properties. Not available for primitive values.
|
|
449
|
+
*
|
|
450
|
+
* @public
|
|
451
|
+
* @param {*} value - Object to protect.
|
|
452
|
+
* @param {string} [globalName] - Whether to add the object to global.
|
|
453
|
+
* @return {*} Object to protect.
|
|
454
|
+
* @throws {*} If the setter of the global throws an exception it is propagated.
|
|
455
|
+
*/
|
|
456
|
+
protect(value, globalName) {
|
|
457
|
+
this._makeProtected(value);
|
|
458
|
+
if (globalName) this.sandbox[globalName] = value;
|
|
459
|
+
return value;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Run the code in VM.
|
|
464
|
+
*
|
|
465
|
+
* @public
|
|
466
|
+
* @param {(string|VMScript)} code - Code to run.
|
|
467
|
+
* @param {(string|Object)} [options] - Options map or filename.
|
|
468
|
+
* @param {string} [options.filename="vm.js"] - Filename that shows up in any stack traces produced from this script.<br>
|
|
469
|
+
* This is only used if code is a String.
|
|
470
|
+
* @return {*} Result of executed code.
|
|
471
|
+
* @throws {SyntaxError} If there is a syntax error in the script.
|
|
472
|
+
* @throws {Error} An error is thrown when the script took to long and there is a timeout.
|
|
473
|
+
* @throws {*} If the script execution terminated with an exception it is propagated.
|
|
474
|
+
*/
|
|
475
|
+
run(code, options) {
|
|
476
|
+
let script;
|
|
477
|
+
let filename;
|
|
478
|
+
|
|
479
|
+
if (typeof options === 'object') {
|
|
480
|
+
filename = options.filename;
|
|
481
|
+
} else {
|
|
482
|
+
filename = options;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (code instanceof VMScript) {
|
|
486
|
+
script = code._compileVM();
|
|
487
|
+
checkAsync(this._allowAsync || !code._hasAsync);
|
|
488
|
+
} else {
|
|
489
|
+
const useFileName = filename || 'vm.js';
|
|
490
|
+
let scriptCode = this._compiler(code, useFileName);
|
|
491
|
+
const ret = transformer(null, scriptCode, false, false, useFileName);
|
|
492
|
+
scriptCode = ret.code;
|
|
493
|
+
checkAsync(this._allowAsync || !ret.hasAsync);
|
|
494
|
+
// Compile the script here so that we don't need to create a instance of VMScript.
|
|
495
|
+
script = new Script(scriptCode, {
|
|
496
|
+
__proto__: null,
|
|
497
|
+
filename: useFileName,
|
|
498
|
+
displayErrors: false
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!this.timeout) {
|
|
503
|
+
return this._runScript(script);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return doWithTimeout(() => {
|
|
507
|
+
return this._runScript(script);
|
|
508
|
+
}, this.timeout);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Run the code in VM.
|
|
513
|
+
*
|
|
514
|
+
* @public
|
|
515
|
+
* @since v3.9.0
|
|
516
|
+
* @param {string} filename - Filename of file to load and execute in a NodeVM.
|
|
517
|
+
* @return {*} Result of executed code.
|
|
518
|
+
* @throws {Error} If filename is not a valid filename.
|
|
519
|
+
* @throws {SyntaxError} If there is a syntax error in the script.
|
|
520
|
+
* @throws {Error} An error is thrown when the script took to long and there is a timeout.
|
|
521
|
+
* @throws {*} If the script execution terminated with an exception it is propagated.
|
|
522
|
+
*/
|
|
523
|
+
runFile(filename) {
|
|
524
|
+
const resolvedFilename = pa.resolve(filename);
|
|
525
|
+
|
|
526
|
+
if (!fs.existsSync(resolvedFilename)) {
|
|
527
|
+
throw new VMError(`Script '${filename}' not found.`);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (fs.statSync(resolvedFilename).isDirectory()) {
|
|
531
|
+
throw new VMError('Script must be file, got directory.');
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return this.run(fs.readFileSync(resolvedFilename, 'utf8'), resolvedFilename);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
exports.VM = VM;
|