From 9d25bb67d957bc2e5425fea7bf7a58b3fc64ff9e Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 12 Jul 2021 14:27:04 -0700 Subject: [PATCH] Fix `filename` option --- src/index.ts | 7 +++++-- test/test.ts | 26 +++++++++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9f5c83f..fcafafb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import { generate } from 'escodegen'; import { parseScript } from 'esprima'; import { visit, namedTypes as n, builders as b } from 'ast-types'; import { Context, RunningScriptOptions } from 'vm'; -import { VM } from 'vm2'; +import { VM, VMScript } from 'vm2'; /** * Compiles sync JavaScript code into JavaScript with async Functions. @@ -138,7 +138,10 @@ namespace degenerator { ): (...args: A) => Promise { const compiled = degenerator(code, names); const vm = new VM(options); - const fn = vm.run(`${compiled};${returnName}`); + const script = new VMScript(`${compiled};${returnName}`, { + filename: options.filename, + }); + const fn = vm.run(script); if (typeof fn !== 'function') { throw new Error( `Expected a "function" to be returned for \`${returnName}\`, but got "${typeof fn}"` diff --git a/test/test.ts b/test/test.ts index e42fa72..e36a82a 100644 --- a/test/test.ts +++ b/test/test.ts @@ -159,26 +159,42 @@ describe('degenerator()', () => { assert.equal(val, 'foo'); }); }); - it('should prevent privilege escalation of untrusted code', async() => { + it('should prevent privilege escalation of untrusted code', async () => { let err; try { const fn = compile( `const f = this.constructor.constructor('return process');`, 'f', - [], + [] ); await fn(); - } catch(_err) { + } catch (_err) { err = _err; } - assert.equal(err.message,'process is not defined') + assert.equal(err.message, 'process is not defined'); }); it('should allow to return synchronous undefined', () => { function u() {} const fn = compile(`${u}`, 'u', ['']); - return fn().then(val => { + return fn().then((val) => { assert.strictEqual(val, undefined); }); }); + it('should support "filename" option', async () => { + function u() { + throw new Error('fail'); + } + let err; + const fn = compile(`${u}`, 'u', [''], { + filename: '/foo/bar/baz.js', + }); + try { + await fn(); + } catch (_err) { + err = _err; + } + assert.strictEqual(err.message, 'fail'); + assert(err.stack.includes('at u (/foo/bar/baz.js:')); + }); }); });