From 45493aaa491460391f6a6a56edd81bbb262eab15 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 22 Feb 2019 00:08:45 +0100 Subject: [PATCH] fix: allow some node modules to be imported in the sandbox --- src/__tests__/module.test.js | 18 ++++++++++--- src/babel/module.js | 52 +++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/__tests__/module.test.js b/src/__tests__/module.test.js index 9f43e1aeb..97cb98a4e 100644 --- a/src/__tests__/module.test.js +++ b/src/__tests__/module.test.js @@ -122,11 +122,23 @@ it('exports the path for non JS/JSON files', () => { expect(mod.require('./sample-asset.png')).toBe('./sample-asset.png'); }); -it('throws when requiring native node modules', () => { +it('returns module when requiring mocked builtin node modules', () => { const mod = new Module(path.resolve(__dirname, '../__fixtures__/test.js')); - expect(() => mod.require('fs')).toThrow( - 'Unable to import "fs". Importing Node builtins is not supported in the sandbox.' + expect(mod.require('path')).toBe(require('path')); +}); + +it('returns null when requiring empty builtin node modules', () => { + const mod = new Module(path.resolve(__dirname, '../__fixtures__/test.js')); + + expect(mod.require('fs')).toBe(null); +}); + +it('throws when requiring unmocked builtin node modules', () => { + const mod = new Module(path.resolve(__dirname, '../__fixtures__/test.js')); + + expect(() => mod.require('perf_hooks')).toThrow( + 'Unable to import "perf_hooks". Importing Node builtins is not supported in the sandbox.' ); }); diff --git a/src/babel/module.js b/src/babel/module.js index 64a52e3ec..16e1804fb 100644 --- a/src/babel/module.js +++ b/src/babel/module.js @@ -17,6 +17,44 @@ const vm = require('vm'); const fs = require('fs'); const path = require('path'); +// Supported node builtins based on the modules polyfilled by webpack +// `true` means module is polyfilled, `false` means module is empty +const builtins = { + assert: true, + buffer: true, + child_process: false, + cluster: false, + console: true, + constants: true, + crypto: true, + dgram: false, + dns: false, + domain: true, + events: true, + fs: false, + http: true, + https: true, + module: false, + net: false, + os: true, + path: true, + punycode: true, + process: true, + querystring: true, + readline: false, + repl: false, + stream: true, + string_decoder: true, + sys: true, + timers: true, + tls: false, + tty: true, + url: true, + util: true, + vm: true, + zlib: true, +}; + // Separate cache for evaled modules let cache = {}; @@ -98,11 +136,23 @@ class Module { } require(id: string) { + if (id in builtins) { + // The module is in the allowed list of builtin node modules + // Ideally we should prevent importing them, but webpack polyfills some + // So we check for the list of polyfills to determine which ones to support + if (builtins[id]) { + /* $FlowFixMe */ + return require(id); + } + + return null; + } + // Resolve module id (and filename) relatively to parent module const filename = this.resolve(id); if (filename === id && !path.isAbsolute(id)) { - // Native Node modules + // The module is a builtin node modules, but not in the allowed list throw new Error( `Unable to import "${id}". Importing Node builtins is not supported in the sandbox.` );