@novolobos/nodevm 3.10.5
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.md +9 -0
- package/README.md +461 -0
- package/bin/vm2 +3 -0
- package/index.d.ts +318 -0
- package/index.js +3 -0
- package/lib/bridge.js +1240 -0
- package/lib/builtin.js +147 -0
- package/lib/cli.js +35 -0
- package/lib/compiler.js +117 -0
- package/lib/events.js +977 -0
- package/lib/filesystem.js +84 -0
- package/lib/main.js +31 -0
- package/lib/nodevm.js +582 -0
- package/lib/resolver-compat.js +237 -0
- package/lib/resolver.js +882 -0
- package/lib/script.js +394 -0
- package/lib/setup-node-sandbox.js +461 -0
- package/lib/setup-sandbox.js +907 -0
- package/lib/transformer.js +198 -0
- package/lib/vm.js +545 -0
- package/package.json +48 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Translate the old options to the new Resolver functionality.
|
|
4
|
+
const {
|
|
5
|
+
Resolver,
|
|
6
|
+
DefaultResolver
|
|
7
|
+
} = require('./resolver');
|
|
8
|
+
const {VMError} = require('./bridge');
|
|
9
|
+
const {DefaultFileSystem} = require('./filesystem');
|
|
10
|
+
const {makeBuiltinsFromLegacyOptions} = require('./builtin');
|
|
11
|
+
const {jsCompiler} = require('./compiler');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Require wrapper to be able to annotate require with webpackIgnore.
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
* @param {string} moduleName - Name of module to load.
|
|
18
|
+
* @return {*} Module exports.
|
|
19
|
+
*/
|
|
20
|
+
function defaultRequire(moduleName) {
|
|
21
|
+
// Set module.parser.javascript.commonjsMagicComments=true in your webpack config.
|
|
22
|
+
// eslint-disable-next-line global-require
|
|
23
|
+
return require(/* webpackIgnore: true */ moduleName);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
|
|
27
|
+
function escapeRegExp(string) {
|
|
28
|
+
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function makeExternalMatcherRegex(obj) {
|
|
32
|
+
return escapeRegExp(obj).replace(/\\\\|\//g, '[\\\\/]')
|
|
33
|
+
.replace(/\\\*\\\*/g, '.*').replace(/\\\*/g, '[^\\\\/]*').replace(/\\\?/g, '[^\\\\/]');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function makeExternalMatcher(obj) {
|
|
37
|
+
const regexString = makeExternalMatcherRegex(obj);
|
|
38
|
+
return new RegExp(`[\\\\/]node_modules[\\\\/]${regexString}(?:[\\\\/](?!(?:.*[\\\\/])?node_modules[\\\\/]).*)?$`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class CustomResolver extends DefaultResolver {
|
|
42
|
+
|
|
43
|
+
constructor(fileSystem, globalPaths, builtinModules, rootPaths, pathContext, customResolver, hostRequire, compiler, strict) {
|
|
44
|
+
super(fileSystem, globalPaths, builtinModules);
|
|
45
|
+
this.rootPaths = rootPaths;
|
|
46
|
+
this.pathContext = pathContext;
|
|
47
|
+
this.customResolver = customResolver;
|
|
48
|
+
this.hostRequire = hostRequire;
|
|
49
|
+
this.compiler = compiler;
|
|
50
|
+
this.strict = strict;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
isPathAllowed(filename) {
|
|
54
|
+
return this.rootPaths === undefined || this.rootPaths.some(path => {
|
|
55
|
+
if (!filename.startsWith(path)) return false;
|
|
56
|
+
const len = path.length;
|
|
57
|
+
if (filename.length === len || (len > 0 && this.fs.isSeparator(path[len-1]))) return true;
|
|
58
|
+
return this.fs.isSeparator(filename[len]);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
loadJS(vm, mod, filename) {
|
|
63
|
+
if (this.pathContext(filename, 'js') !== 'host') return super.loadJS(vm, mod, filename);
|
|
64
|
+
const m = this.hostRequire(filename);
|
|
65
|
+
mod.exports = vm.readonly(m);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
loadNode(vm, mod, filename) {
|
|
69
|
+
if (this.pathContext(filename, 'node') !== 'host') return super.loadNode(vm, mod, filename);
|
|
70
|
+
const m = this.hostRequire(filename);
|
|
71
|
+
mod.exports = vm.readonly(m);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
customResolve(x, path, extList) {
|
|
75
|
+
if (this.customResolver === undefined) return undefined;
|
|
76
|
+
const resolved = this.customResolver(x, path);
|
|
77
|
+
if (!resolved) return undefined;
|
|
78
|
+
if (typeof resolved === 'string') {
|
|
79
|
+
return this.loadAsFileOrDirectory(resolved, extList);
|
|
80
|
+
}
|
|
81
|
+
const {module=x, path: resolvedPath} = resolved;
|
|
82
|
+
return this.loadNodeModules(module, [resolvedPath], extList);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getCompiler(filename) {
|
|
86
|
+
return this.compiler;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
isStrict(filename) {
|
|
90
|
+
return this.strict;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class LegacyResolver extends CustomResolver {
|
|
96
|
+
|
|
97
|
+
constructor(fileSystem, globalPaths, builtinModules, rootPaths, pathContext, customResolver, hostRequire, compiler, strict, externals, allowTransitive) {
|
|
98
|
+
super(fileSystem, globalPaths, builtinModules, rootPaths, pathContext, customResolver, hostRequire, compiler, strict);
|
|
99
|
+
this.externals = externals.map(makeExternalMatcher);
|
|
100
|
+
this.externalCache = externals.map(pattern => new RegExp(makeExternalMatcherRegex(pattern)));
|
|
101
|
+
this.currMod = undefined;
|
|
102
|
+
this.trustedMods = new WeakMap();
|
|
103
|
+
this.allowTransitive = allowTransitive;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isPathAllowed(path) {
|
|
107
|
+
return this.isPathAllowedForModule(path, this.currMod);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
isPathAllowedForModule(path, mod) {
|
|
111
|
+
if (!super.isPathAllowed(path)) return false;
|
|
112
|
+
if (mod) {
|
|
113
|
+
if (mod.allowTransitive) return true;
|
|
114
|
+
if (path.startsWith(mod.path)) {
|
|
115
|
+
const rem = path.slice(mod.path.length);
|
|
116
|
+
if (!/(?:^|[\\\\/])node_modules(?:$|[\\\\/])/.test(rem)) return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return this.externals.some(regex => regex.test(path));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
registerModule(mod, filename, path, parent, direct) {
|
|
123
|
+
const trustedParent = this.trustedMods.get(parent);
|
|
124
|
+
this.trustedMods.set(mod, {
|
|
125
|
+
filename,
|
|
126
|
+
path,
|
|
127
|
+
paths: this.genLookupPaths(path),
|
|
128
|
+
allowTransitive: this.allowTransitive &&
|
|
129
|
+
((direct && trustedParent && trustedParent.allowTransitive) || this.externals.some(regex => regex.test(filename)))
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
resolveFull(mod, x, options, extList, direct) {
|
|
134
|
+
this.currMod = undefined;
|
|
135
|
+
if (!direct) return super.resolveFull(mod, x, options, extList, false);
|
|
136
|
+
const trustedMod = this.trustedMods.get(mod);
|
|
137
|
+
if (!trustedMod || mod.path !== trustedMod.path) return super.resolveFull(mod, x, options, extList, false);
|
|
138
|
+
const paths = [...mod.paths];
|
|
139
|
+
if (paths.length !== trustedMod.paths.length) return super.resolveFull(mod, x, options, extList, false);
|
|
140
|
+
for (let i = 0; i < paths.length; i++) {
|
|
141
|
+
if (paths[i] !== trustedMod.paths[i]) {
|
|
142
|
+
return super.resolveFull(mod, x, options, extList, false);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
this.currMod = trustedMod;
|
|
147
|
+
return super.resolveFull(trustedMod, x, options, extList, true);
|
|
148
|
+
} finally {
|
|
149
|
+
this.currMod = undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
checkAccess(mod, filename) {
|
|
154
|
+
const trustedMod = this.trustedMods.get(mod);
|
|
155
|
+
if ((!trustedMod || trustedMod.filename !== filename) && !this.isPathAllowedForModule(filename, undefined)) {
|
|
156
|
+
throw new VMError(`Module '${filename}' is not allowed to be required. The path is outside the border!`, 'EDENIED');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
loadJS(vm, mod, filename) {
|
|
161
|
+
if (this.pathContext(filename, 'js') !== 'host') {
|
|
162
|
+
const trustedMod = this.trustedMods.get(mod);
|
|
163
|
+
const script = this.readScript(filename);
|
|
164
|
+
vm.run(script, {filename, strict: this.isStrict(filename), module: mod, wrapper: 'none', dirname: trustedMod ? trustedMod.path : mod.path});
|
|
165
|
+
} else {
|
|
166
|
+
const m = this.hostRequire(filename);
|
|
167
|
+
mod.exports = vm.readonly(m);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
customResolve(x, path, extList) {
|
|
172
|
+
if (this.customResolver === undefined) return undefined;
|
|
173
|
+
if (!(this.pathIsAbsolute(x) || this.pathIsRelative(x))) {
|
|
174
|
+
if (!this.externalCache.some(regex => regex.test(x))) return undefined;
|
|
175
|
+
}
|
|
176
|
+
const resolved = this.customResolver(x, path);
|
|
177
|
+
if (!resolved) return undefined;
|
|
178
|
+
if (typeof resolved === 'string') {
|
|
179
|
+
this.externals.push(new RegExp('^' + escapeRegExp(resolved)));
|
|
180
|
+
return this.loadAsFileOrDirectory(resolved, extList);
|
|
181
|
+
}
|
|
182
|
+
const {module=x, path: resolvedPath} = resolved;
|
|
183
|
+
this.externals.push(new RegExp('^' + escapeRegExp(resolvedPath)));
|
|
184
|
+
return this.loadNodeModules(module, [resolvedPath], extList);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const DEFAULT_FS = new DefaultFileSystem();
|
|
190
|
+
|
|
191
|
+
const DENY_RESOLVER = new Resolver(DEFAULT_FS, [], new Map());
|
|
192
|
+
|
|
193
|
+
function makeResolverFromLegacyOptions(options, override, compiler) {
|
|
194
|
+
if (!options) {
|
|
195
|
+
if (!override) return DENY_RESOLVER;
|
|
196
|
+
const builtins = makeBuiltinsFromLegacyOptions(undefined, defaultRequire, undefined, override);
|
|
197
|
+
return new Resolver(DEFAULT_FS, [], builtins);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const {
|
|
201
|
+
builtin: builtinOpt,
|
|
202
|
+
mock: mockOpt,
|
|
203
|
+
external: externalOpt,
|
|
204
|
+
root: rootPaths,
|
|
205
|
+
resolve: customResolver,
|
|
206
|
+
customRequire: hostRequire = defaultRequire,
|
|
207
|
+
context = 'host',
|
|
208
|
+
strict = true,
|
|
209
|
+
fs: fsOpt = DEFAULT_FS,
|
|
210
|
+
} = options;
|
|
211
|
+
|
|
212
|
+
const builtins = makeBuiltinsFromLegacyOptions(builtinOpt, hostRequire, mockOpt, override);
|
|
213
|
+
|
|
214
|
+
if (!externalOpt) return new Resolver(fsOpt, [], builtins);
|
|
215
|
+
|
|
216
|
+
if (!compiler) compiler = jsCompiler;
|
|
217
|
+
|
|
218
|
+
const checkedRootPaths = rootPaths ? (Array.isArray(rootPaths) ? rootPaths : [rootPaths]).map(f => fsOpt.resolve(f)) : undefined;
|
|
219
|
+
|
|
220
|
+
const pathContext = typeof context === 'function' ? context : (() => context);
|
|
221
|
+
|
|
222
|
+
if (typeof externalOpt !== 'object') {
|
|
223
|
+
return new CustomResolver(fsOpt, [], builtins, checkedRootPaths, pathContext, customResolver, hostRequire, compiler, strict);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let transitive = false;
|
|
227
|
+
let external = undefined;
|
|
228
|
+
if (Array.isArray(externalOpt)) {
|
|
229
|
+
external = externalOpt;
|
|
230
|
+
} else {
|
|
231
|
+
external = externalOpt.modules;
|
|
232
|
+
transitive = context !== 'host' && externalOpt.transitive;
|
|
233
|
+
}
|
|
234
|
+
return new LegacyResolver(fsOpt, [], builtins, checkedRootPaths, pathContext, customResolver, hostRequire, compiler, strict, external, transitive);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
exports.makeResolverFromLegacyOptions = makeResolverFromLegacyOptions;
|