Comparing version 3.9.11 to 3.9.12
@@ -0,1 +1,6 @@ | ||
v3.9.12 (2022-11-29) | ||
-------------------- | ||
[new] Add file system API. | ||
[fix] Fix parsing error with object patter in catch clause. | ||
v3.9.11 (2022-08-28) | ||
@@ -2,0 +7,0 @@ -------------------- |
import {EventEmitter} from 'events'; | ||
import fs from 'fs'; | ||
import pa from 'path'; | ||
/** | ||
* Interface for nodes fs module | ||
*/ | ||
export interface VMFS { | ||
/** Implements fs.statSync */ | ||
statSync: typeof fs.statSync; | ||
/** Implements fs.readFileSync */ | ||
readFileSync: typeof fs.readFileSync; | ||
} | ||
/** | ||
* Interface for nodes path module | ||
*/ | ||
export interface VMPath { | ||
/** Implements path.resolve */ | ||
resolve: typeof pa.resolve; | ||
/** Implements path.isAbsolute */ | ||
isAbsolute: typeof pa.isAbsolute; | ||
/** Implements path.join */ | ||
join: typeof pa.join; | ||
/** Implements path.basename */ | ||
basename: typeof pa.basename; | ||
/** Implements path.dirname */ | ||
dirname: typeof pa.dirname; | ||
/** Implements fs.statSync */ | ||
statSync: typeof fs.statSync; | ||
/** Implements fs.readFileSync */ | ||
readFileSync: typeof fs.readFileSync; | ||
} | ||
/** | ||
* Custom file system which abstracts functions from node's fs and path modules. | ||
*/ | ||
export interface VMFileSystemInterface implements VMFS, VMPath { | ||
/** Implements (sep) => sep === path.sep */ | ||
isSeparator(char: string): boolean; | ||
} | ||
/** | ||
* Implementation of a default file system. | ||
*/ | ||
export class VMFileSystem implements VMFileSystemInterface { | ||
constructor(options?: {fs?: VMFS, path?: VMPath}); | ||
} | ||
/** | ||
* Require options for a VM | ||
@@ -29,2 +76,4 @@ */ | ||
strict?: boolean; | ||
/** FileSystem to load files from */ | ||
fs?: VMFileSystemInterface; | ||
} | ||
@@ -31,0 +80,0 @@ |
@@ -15,2 +15,5 @@ 'use strict'; | ||
} = require('./nodevm'); | ||
const { | ||
VMFileSystem | ||
} = require('./filesystem'); | ||
@@ -21,1 +24,2 @@ exports.VMError = VMError; | ||
exports.VM = VM; | ||
exports.VMFileSystem = VMFileSystem; |
@@ -6,3 +6,2 @@ 'use strict'; | ||
const fs = require('fs'); | ||
const pa = require('path'); | ||
const nmod = require('module'); | ||
@@ -19,2 +18,3 @@ const {EventEmitter} = require('events'); | ||
const {VMError} = require('./bridge'); | ||
const {DefaultFileSystem} = require('./filesystem'); | ||
@@ -51,4 +51,4 @@ /** | ||
constructor(builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict, externals, allowTransitive) { | ||
super(builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict); | ||
constructor(fileSystem, builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict, externals, allowTransitive) { | ||
super(fileSystem, builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict); | ||
this.externals = externals; | ||
@@ -270,3 +270,5 @@ this.currMod = undefined; | ||
const DENY_RESOLVER = new Resolver({__proto__: null}, [], id => { | ||
const DEFAULT_FS = new DefaultFileSystem(); | ||
const DENY_RESOLVER = new Resolver(DEFAULT_FS, {__proto__: null}, [], id => { | ||
throw new VMError(`Access denied to require '${id}'`, 'EDENIED'); | ||
@@ -279,3 +281,3 @@ }); | ||
const builtins = genBuiltinsFromOptions(vm, undefined, undefined, override); | ||
return new Resolver(builtins, [], defaultRequire); | ||
return new Resolver(DEFAULT_FS, builtins, [], defaultRequire); | ||
} | ||
@@ -292,2 +294,3 @@ | ||
strict = true, | ||
fs: fsOpt = DEFAULT_FS, | ||
} = options; | ||
@@ -297,7 +300,7 @@ | ||
if (!externalOpt) return new Resolver(builtins, [], hostRequire); | ||
if (!externalOpt) return new Resolver(fsOpt, builtins, [], hostRequire); | ||
let checkPath; | ||
if (rootPaths) { | ||
const checkedRootPaths = (Array.isArray(rootPaths) ? rootPaths : [rootPaths]).map(f => pa.resolve(f)); | ||
const checkedRootPaths = (Array.isArray(rootPaths) ? rootPaths : [rootPaths]).map(f => fsOpt.resolve(f)); | ||
checkPath = (filename) => { | ||
@@ -307,5 +310,4 @@ return checkedRootPaths.some(path => { | ||
const len = path.length; | ||
if (filename.length === len || (len > 0 && path[len-1] === pa.sep)) return true; | ||
const sep = filename[len]; | ||
return sep === '/' || sep === pa.sep; | ||
if (filename.length === len || (len > 0 && fsOpt.isSeparator(path[len-1]))) return true; | ||
return fsOpt.isSeparator(filename[len]); | ||
}); | ||
@@ -337,3 +339,3 @@ }; | ||
if (typeof externalOpt !== 'object') { | ||
return new DefaultResolver(builtins, checkPath, [], () => context, newCustomResolver, hostRequire, compiler, strict); | ||
return new DefaultResolver(fsOpt, builtins, checkPath, [], () => context, newCustomResolver, hostRequire, compiler, strict); | ||
} | ||
@@ -349,5 +351,5 @@ | ||
externals = external.map(makeExternalMatcher); | ||
return new LegacyResolver(builtins, checkPath, [], () => context, newCustomResolver, hostRequire, compiler, strict, externals, transitive); | ||
return new LegacyResolver(fsOpt, builtins, checkPath, [], () => context, newCustomResolver, hostRequire, compiler, strict, externals, transitive); | ||
} | ||
exports.resolverFromOptions = resolverFromOptions; |
@@ -5,5 +5,2 @@ 'use strict'; | ||
const pa = require('path'); | ||
const fs = require('fs'); | ||
const { | ||
@@ -28,3 +25,4 @@ VMError | ||
constructor(builtinModules, globalPaths, hostRequire) { | ||
constructor(fs, builtinModules, globalPaths, hostRequire) { | ||
this.fs = fs; | ||
this.builtinModules = builtinModules; | ||
@@ -40,3 +38,3 @@ this.globalPaths = globalPaths; | ||
pathResolve(path) { | ||
return pa.resolve(path); | ||
return this.fs.resolve(path); | ||
} | ||
@@ -49,19 +47,19 @@ | ||
if (path.length <= idx) return false; | ||
return path[idx] === '/' || path[idx] === pa.sep; | ||
return this.fs.isSeparator(path[idx]); | ||
} | ||
pathIsAbsolute(path) { | ||
return pa.isAbsolute(path); | ||
return path !== '' && (this.fs.isSeparator(path[0]) || this.fs.isAbsolute(path)); | ||
} | ||
pathConcat(...paths) { | ||
return pa.join(...paths); | ||
return this.fs.join(...paths); | ||
} | ||
pathBasename(path) { | ||
return pa.basename(path); | ||
return this.fs.basename(path); | ||
} | ||
pathDirname(path) { | ||
return pa.dirname(path); | ||
return this.fs.dirname(path); | ||
} | ||
@@ -147,4 +145,4 @@ | ||
constructor(builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict) { | ||
super(builtinModules, globalPaths, hostRequire); | ||
constructor(fs, builtinModules, checkPath, globalPaths, pathContext, customResolver, hostRequire, compiler, strict) { | ||
super(fs, builtinModules, globalPaths, hostRequire); | ||
this.checkPath = checkPath; | ||
@@ -165,3 +163,3 @@ this.pathContext = pathContext; | ||
try { | ||
const stat = fs.statSync(path, {__proto__: null, throwIfNoEntry: false}); | ||
const stat = this.fs.statSync(path, {__proto__: null, throwIfNoEntry: false}); | ||
return stat && stat.isDirectory(); | ||
@@ -175,3 +173,3 @@ } catch (e) { | ||
try { | ||
const stat = fs.statSync(path, {__proto__: null, throwIfNoEntry: false}); | ||
const stat = this.fs.statSync(path, {__proto__: null, throwIfNoEntry: false}); | ||
return stat && stat.isFile(); | ||
@@ -184,3 +182,3 @@ } catch (e) { | ||
readFile(path) { | ||
return fs.readFileSync(path, {encoding: 'utf8'}); | ||
return this.fs.readFileSync(path, {encoding: 'utf8'}); | ||
} | ||
@@ -187,0 +185,0 @@ |
@@ -110,3 +110,3 @@ /* global host, data, VMError */ | ||
const path = resolver.pathDirname(filename); | ||
const path = resolver.fs.dirname(filename); | ||
const module = new Module(filename, path, mod); | ||
@@ -150,3 +150,3 @@ resolver.registerModule(module, filename, path, mod, direct); | ||
function findBestExtensionHandler(filename) { | ||
const name = resolver.pathBasename(filename); | ||
const name = resolver.fs.basename(filename); | ||
for (let i = 0; (i = localStringPrototypeIndexOf(name, '.', i + 1)) !== -1;) { | ||
@@ -153,0 +153,0 @@ const ext = localStringPrototypeSlice(name, i); |
@@ -106,2 +106,3 @@ | ||
let internStateValiable = undefined; | ||
let tmpname = 'VM2_INTERNAL_TMPNAME'; | ||
@@ -116,11 +117,26 @@ acornWalkFull(ast, (node, state, type) => { | ||
if (param) { | ||
const name = assertType(param, 'Identifier').name; | ||
const cBody = assertType(node.body, 'BlockStatement'); | ||
if (cBody.body.length > 0) { | ||
if (param.type === 'ObjectPattern') { | ||
insertions.push({ | ||
__proto__: null, | ||
pos: cBody.body[0].start, | ||
pos: node.start, | ||
order: TO_RIGHT, | ||
code: `catch($tmpname){try{throw ${INTERNAL_STATE_NAME}.handleException($tmpname);}` | ||
}); | ||
insertions.push({ | ||
__proto__: null, | ||
pos: node.body.end, | ||
order: TO_LEFT, | ||
code: `${name}=${INTERNAL_STATE_NAME}.handleException(${name});` | ||
code: `}` | ||
}); | ||
} else { | ||
const name = assertType(param, 'Identifier').name; | ||
const cBody = assertType(node.body, 'BlockStatement'); | ||
if (cBody.body.length > 0) { | ||
insertions.push({ | ||
__proto__: null, | ||
pos: cBody.body[0].start, | ||
order: TO_LEFT, | ||
code: `${name}=${INTERNAL_STATE_NAME}.handleException(${name});` | ||
}); | ||
} | ||
} | ||
@@ -146,2 +162,4 @@ } | ||
} | ||
} else if (node.name.startsWith(tmpname)) { | ||
tmpname = node.name + '_UNIQUE'; | ||
} | ||
@@ -174,3 +192,3 @@ } else if (nodeType === 'ImportExpression') { | ||
const change = insertions[i]; | ||
ncode += code.substring(curr, change.pos) + change.code; | ||
ncode += code.substring(curr, change.pos) + change.code.replace(/\$tmpname/g, tmpname); | ||
curr = change.pos; | ||
@@ -177,0 +195,0 @@ } |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "3.9.11", | ||
"version": "3.9.12", | ||
"main": "index.js", | ||
@@ -19,0 +19,0 @@ "sideEffects": false, |
@@ -149,2 +149,3 @@ # vm2 [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Package Quality][quality-image]][quality-url] [![Node.js CI](https://github.com/patriksimek/vm2/actions/workflows/node-test.yml/badge.svg)](https://github.com/patriksimek/vm2/actions/workflows/node-test.yml) [![Known Vulnerabilities][snyk-image]][snyk-url] | ||
* `require.strict` - `false` to not force strict mode on modules loaded by require (default: `true`). | ||
* `require.fs` - Custom file system implementation. | ||
* `nesting` - **WARNING**: Allowing this is a security risk as scripts can create a NodeVM which can require any host module. `true` to enable VMs nesting (default: `false`). | ||
@@ -382,6 +383,7 @@ * `wrapper` - `commonjs` (default) to wrap script into CommonJS wrapper, `none` to retrieve value returned by the script. | ||
* It is not possible to define a class that extends a proxied class. | ||
* It is not possible to define a class that extends a proxied class. This includes using a proxied class in `Object.create`. | ||
* Direct eval does not work. | ||
* Logging sandbox arrays will repeat the array part in the properties. | ||
* Source code transformations can result a different source string for a function. | ||
* There are ways to crash the node process from inside the sandbox. | ||
@@ -388,0 +390,0 @@ ## Deployment |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
211310
23
5565
411