├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── index.ts └── models │ ├── vm-options.ts │ ├── vm-require-options.ts │ └── vm.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .DS_Store 4 | *.log 5 | *.log* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Nersent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easy-vm 2 | 3 | `easy-vm` is a simple Node.js library which helps with running securely untrusted code with whitelisted Node modules. 4 | 5 | # Installation 6 | 7 | ```bash 8 | $ npm install easy-vm 9 | ``` 10 | 11 | # Quick example 12 | ```javascript 13 | const EasyVM = require('easy-vm'); 14 | 15 | const vm = new EasyVM({ 16 | console: true, 17 | sandbox: { 18 | test: 'A test variable' 19 | }, 20 | require: { 21 | builtin: ['fs'], 22 | mock: { 23 | fs: { 24 | readFile: (path: string) => { 25 | console.log("Nice try!"); 26 | } 27 | } 28 | } 29 | } 30 | }); 31 | 32 | vm.run(` 33 | const fs = require('fs'); 34 | fs.readFile(''); // Outputs: Nice try! 35 | 36 | console.log(test); // Outputs: A test variable 37 | `); 38 | ``` 39 | 40 | # Documentation 41 | 42 | ## Class `EasyVM` 43 | 44 | An `EasyVM` can be used to create a sandbox. 45 | 46 | ### `new EasyVM(options)` 47 | 48 | * `options` VMOptions 49 | * `console` boolean - Whether to enable console in the sandbox or not. 50 | * `sandbox` object - A global object in VM 51 | * `require` VMRequireOptions | false - False to disable require or object to enable require with options. 52 | * `builtin` string[] - Array of allowed builtin modules, Use `['*']` to accept all. 53 | * `mock` object - Collection of mocked Node modules. 54 | 55 | #### Methods 56 | 57 | `EasyVM.run(code, filename)` 58 | 59 | * `code` string 60 | * `filename` string (optional) - Path to which Node's `require()` relates. 61 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easy-vm", 3 | "version": "1.2.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.5.5", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", 10 | "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.5.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", 19 | "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "@fimbul/bifrost": { 28 | "version": "0.17.0", 29 | "resolved": "https://registry.npmjs.org/@fimbul/bifrost/-/bifrost-0.17.0.tgz", 30 | "integrity": "sha512-gVTkJAOef5HtN6LPmrtt5fAUmBywwlgmObsU3FBhPoNeXPLaIl2zywXkJEtvvVLQnaFmtff3x+wIj5lHRCDE3Q==", 31 | "dev": true, 32 | "requires": { 33 | "@fimbul/ymir": "^0.17.0", 34 | "get-caller-file": "^2.0.0", 35 | "tslib": "^1.8.1", 36 | "tsutils": "^3.5.0" 37 | }, 38 | "dependencies": { 39 | "tsutils": { 40 | "version": "3.14.0", 41 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", 42 | "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", 43 | "dev": true, 44 | "requires": { 45 | "tslib": "^1.8.1" 46 | } 47 | } 48 | } 49 | }, 50 | "@fimbul/ymir": { 51 | "version": "0.17.0", 52 | "resolved": "https://registry.npmjs.org/@fimbul/ymir/-/ymir-0.17.0.tgz", 53 | "integrity": "sha512-xMXM9KTXRLHLVS6dnX1JhHNEkmWHcAVCQ/4+DA1KKwC/AFnGHzu/7QfQttEPgw3xplT+ILf9e3i64jrFwB3JtA==", 54 | "dev": true, 55 | "requires": { 56 | "inversify": "^5.0.0", 57 | "reflect-metadata": "^0.1.12", 58 | "tslib": "^1.8.1" 59 | } 60 | }, 61 | "@types/node": { 62 | "version": "12.7.4", 63 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz", 64 | "integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==", 65 | "dev": true 66 | }, 67 | "ansi-styles": { 68 | "version": "3.2.1", 69 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 70 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 71 | "requires": { 72 | "color-convert": "^1.9.0" 73 | } 74 | }, 75 | "argparse": { 76 | "version": "1.0.10", 77 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 78 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 79 | "dev": true, 80 | "requires": { 81 | "sprintf-js": "~1.0.2" 82 | } 83 | }, 84 | "balanced-match": { 85 | "version": "1.0.0", 86 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 87 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 88 | "dev": true 89 | }, 90 | "big.js": { 91 | "version": "5.2.2", 92 | "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", 93 | "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" 94 | }, 95 | "brace-expansion": { 96 | "version": "1.1.11", 97 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 98 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 99 | "dev": true, 100 | "requires": { 101 | "balanced-match": "^1.0.0", 102 | "concat-map": "0.0.1" 103 | } 104 | }, 105 | "braces": { 106 | "version": "3.0.2", 107 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 108 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 109 | "requires": { 110 | "fill-range": "^7.0.1" 111 | } 112 | }, 113 | "builtin-modules": { 114 | "version": "1.1.1", 115 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 116 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 117 | "dev": true 118 | }, 119 | "chalk": { 120 | "version": "2.4.2", 121 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 122 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 123 | "requires": { 124 | "ansi-styles": "^3.2.1", 125 | "escape-string-regexp": "^1.0.5", 126 | "supports-color": "^5.3.0" 127 | } 128 | }, 129 | "color-convert": { 130 | "version": "1.9.3", 131 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 132 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 133 | "requires": { 134 | "color-name": "1.1.3" 135 | } 136 | }, 137 | "color-name": { 138 | "version": "1.1.3", 139 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 140 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 141 | }, 142 | "commander": { 143 | "version": "2.20.0", 144 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 145 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", 146 | "dev": true 147 | }, 148 | "concat-map": { 149 | "version": "0.0.1", 150 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 151 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 152 | "dev": true 153 | }, 154 | "core-util-is": { 155 | "version": "1.0.2", 156 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 157 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 158 | }, 159 | "diff": { 160 | "version": "3.5.0", 161 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 162 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 163 | "dev": true 164 | }, 165 | "doctrine": { 166 | "version": "0.7.2", 167 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", 168 | "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", 169 | "dev": true, 170 | "requires": { 171 | "esutils": "^1.1.6", 172 | "isarray": "0.0.1" 173 | }, 174 | "dependencies": { 175 | "esutils": { 176 | "version": "1.1.6", 177 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", 178 | "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=", 179 | "dev": true 180 | }, 181 | "isarray": { 182 | "version": "0.0.1", 183 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 184 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 185 | "dev": true 186 | } 187 | } 188 | }, 189 | "emojis-list": { 190 | "version": "2.1.0", 191 | "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", 192 | "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" 193 | }, 194 | "enhanced-resolve": { 195 | "version": "4.1.0", 196 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", 197 | "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", 198 | "requires": { 199 | "graceful-fs": "^4.1.2", 200 | "memory-fs": "^0.4.0", 201 | "tapable": "^1.0.0" 202 | } 203 | }, 204 | "errno": { 205 | "version": "0.1.7", 206 | "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", 207 | "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", 208 | "requires": { 209 | "prr": "~1.0.1" 210 | } 211 | }, 212 | "escape-string-regexp": { 213 | "version": "1.0.5", 214 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 215 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 216 | }, 217 | "esprima": { 218 | "version": "4.0.1", 219 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 220 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 221 | "dev": true 222 | }, 223 | "esutils": { 224 | "version": "2.0.3", 225 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 226 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 227 | "dev": true 228 | }, 229 | "fill-range": { 230 | "version": "7.0.1", 231 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 232 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 233 | "requires": { 234 | "to-regex-range": "^5.0.1" 235 | } 236 | }, 237 | "fs.realpath": { 238 | "version": "1.0.0", 239 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 240 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 241 | "dev": true 242 | }, 243 | "get-caller-file": { 244 | "version": "2.0.5", 245 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 246 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 247 | "dev": true 248 | }, 249 | "glob": { 250 | "version": "7.1.4", 251 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 252 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 253 | "dev": true, 254 | "requires": { 255 | "fs.realpath": "^1.0.0", 256 | "inflight": "^1.0.4", 257 | "inherits": "2", 258 | "minimatch": "^3.0.4", 259 | "once": "^1.3.0", 260 | "path-is-absolute": "^1.0.0" 261 | } 262 | }, 263 | "graceful-fs": { 264 | "version": "4.1.15", 265 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 266 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" 267 | }, 268 | "has-flag": { 269 | "version": "3.0.0", 270 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 271 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 272 | }, 273 | "inflight": { 274 | "version": "1.0.6", 275 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 276 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 277 | "dev": true, 278 | "requires": { 279 | "once": "^1.3.0", 280 | "wrappy": "1" 281 | } 282 | }, 283 | "inherits": { 284 | "version": "2.0.4", 285 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 286 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 287 | }, 288 | "inversify": { 289 | "version": "5.0.1", 290 | "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", 291 | "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==", 292 | "dev": true 293 | }, 294 | "is-number": { 295 | "version": "7.0.0", 296 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 297 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 298 | }, 299 | "isarray": { 300 | "version": "1.0.0", 301 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 302 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 303 | }, 304 | "js-tokens": { 305 | "version": "4.0.0", 306 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 307 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 308 | "dev": true 309 | }, 310 | "js-yaml": { 311 | "version": "3.13.1", 312 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 313 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 314 | "dev": true, 315 | "requires": { 316 | "argparse": "^1.0.7", 317 | "esprima": "^4.0.0" 318 | } 319 | }, 320 | "json5": { 321 | "version": "1.0.1", 322 | "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", 323 | "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", 324 | "requires": { 325 | "minimist": "^1.2.0" 326 | } 327 | }, 328 | "loader-utils": { 329 | "version": "1.2.3", 330 | "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", 331 | "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", 332 | "requires": { 333 | "big.js": "^5.2.2", 334 | "emojis-list": "^2.0.0", 335 | "json5": "^1.0.1" 336 | } 337 | }, 338 | "memory-fs": { 339 | "version": "0.4.1", 340 | "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", 341 | "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", 342 | "requires": { 343 | "errno": "^0.1.3", 344 | "readable-stream": "^2.0.1" 345 | } 346 | }, 347 | "micromatch": { 348 | "version": "4.0.2", 349 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", 350 | "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", 351 | "requires": { 352 | "braces": "^3.0.1", 353 | "picomatch": "^2.0.5" 354 | } 355 | }, 356 | "minimatch": { 357 | "version": "3.0.4", 358 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 359 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 360 | "dev": true, 361 | "requires": { 362 | "brace-expansion": "^1.1.7" 363 | } 364 | }, 365 | "minimist": { 366 | "version": "1.2.0", 367 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 368 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 369 | }, 370 | "mkdirp": { 371 | "version": "0.5.1", 372 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 373 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 374 | "dev": true, 375 | "requires": { 376 | "minimist": "0.0.8" 377 | }, 378 | "dependencies": { 379 | "minimist": { 380 | "version": "0.0.8", 381 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 382 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 383 | "dev": true 384 | } 385 | } 386 | }, 387 | "once": { 388 | "version": "1.4.0", 389 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 390 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 391 | "dev": true, 392 | "requires": { 393 | "wrappy": "1" 394 | } 395 | }, 396 | "path-is-absolute": { 397 | "version": "1.0.1", 398 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 399 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 400 | "dev": true 401 | }, 402 | "path-parse": { 403 | "version": "1.0.6", 404 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 405 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 406 | "dev": true 407 | }, 408 | "picomatch": { 409 | "version": "2.0.7", 410 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", 411 | "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==" 412 | }, 413 | "prettier": { 414 | "version": "1.18.2", 415 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", 416 | "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", 417 | "dev": true 418 | }, 419 | "process-nextick-args": { 420 | "version": "2.0.1", 421 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 422 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 423 | }, 424 | "prr": { 425 | "version": "1.0.1", 426 | "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", 427 | "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" 428 | }, 429 | "readable-stream": { 430 | "version": "2.3.6", 431 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 432 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 433 | "requires": { 434 | "core-util-is": "~1.0.0", 435 | "inherits": "~2.0.3", 436 | "isarray": "~1.0.0", 437 | "process-nextick-args": "~2.0.0", 438 | "safe-buffer": "~5.1.1", 439 | "string_decoder": "~1.1.1", 440 | "util-deprecate": "~1.0.1" 441 | } 442 | }, 443 | "reflect-metadata": { 444 | "version": "0.1.13", 445 | "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", 446 | "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", 447 | "dev": true 448 | }, 449 | "resolve": { 450 | "version": "1.12.0", 451 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", 452 | "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", 453 | "dev": true, 454 | "requires": { 455 | "path-parse": "^1.0.6" 456 | } 457 | }, 458 | "safe-buffer": { 459 | "version": "5.1.2", 460 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 461 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 462 | }, 463 | "semver": { 464 | "version": "5.7.1", 465 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 466 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 467 | "dev": true 468 | }, 469 | "sprintf-js": { 470 | "version": "1.0.3", 471 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 472 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 473 | "dev": true 474 | }, 475 | "string_decoder": { 476 | "version": "1.1.1", 477 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 478 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 479 | "requires": { 480 | "safe-buffer": "~5.1.0" 481 | } 482 | }, 483 | "supports-color": { 484 | "version": "5.5.0", 485 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 486 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 487 | "requires": { 488 | "has-flag": "^3.0.0" 489 | } 490 | }, 491 | "tapable": { 492 | "version": "1.1.3", 493 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", 494 | "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" 495 | }, 496 | "to-regex-range": { 497 | "version": "5.0.1", 498 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 499 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 500 | "requires": { 501 | "is-number": "^7.0.0" 502 | } 503 | }, 504 | "ts-loader": { 505 | "version": "6.0.4", 506 | "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.0.4.tgz", 507 | "integrity": "sha512-p2zJYe7OtwR+49kv4gs7v4dMrfYD1IPpOtqiSPCbe8oR+4zEBtdHwzM7A7M91F+suReqgzZrlClk4LRSSp882g==", 508 | "requires": { 509 | "chalk": "^2.3.0", 510 | "enhanced-resolve": "^4.0.0", 511 | "loader-utils": "^1.0.2", 512 | "micromatch": "^4.0.0", 513 | "semver": "^6.0.0" 514 | }, 515 | "dependencies": { 516 | "semver": { 517 | "version": "6.1.2", 518 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", 519 | "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==" 520 | } 521 | } 522 | }, 523 | "tslib": { 524 | "version": "1.10.0", 525 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 526 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", 527 | "dev": true 528 | }, 529 | "tslint": { 530 | "version": "5.19.0", 531 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz", 532 | "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==", 533 | "dev": true, 534 | "requires": { 535 | "@babel/code-frame": "^7.0.0", 536 | "builtin-modules": "^1.1.1", 537 | "chalk": "^2.3.0", 538 | "commander": "^2.12.1", 539 | "diff": "^3.2.0", 540 | "glob": "^7.1.1", 541 | "js-yaml": "^3.13.1", 542 | "minimatch": "^3.0.4", 543 | "mkdirp": "^0.5.1", 544 | "resolve": "^1.3.2", 545 | "semver": "^5.3.0", 546 | "tslib": "^1.8.0", 547 | "tsutils": "^2.29.0" 548 | } 549 | }, 550 | "tslint-config-airbnb": { 551 | "version": "5.11.1", 552 | "resolved": "https://registry.npmjs.org/tslint-config-airbnb/-/tslint-config-airbnb-5.11.1.tgz", 553 | "integrity": "sha512-hkaittm2607vVMe8eotANGN1CimD5tor7uoY3ypg2VTtEcDB/KGWYbJOz58t8LI4cWSyWtgqYQ5F0HwKxxhlkQ==", 554 | "dev": true, 555 | "requires": { 556 | "tslint-consistent-codestyle": "^1.14.1", 557 | "tslint-eslint-rules": "^5.4.0", 558 | "tslint-microsoft-contrib": "~5.2.1" 559 | } 560 | }, 561 | "tslint-config-prettier": { 562 | "version": "1.18.0", 563 | "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", 564 | "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", 565 | "dev": true 566 | }, 567 | "tslint-consistent-codestyle": { 568 | "version": "1.15.1", 569 | "resolved": "https://registry.npmjs.org/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.15.1.tgz", 570 | "integrity": "sha512-38Y3Dz4zcABe/PlPAQSGNEWPGVq0OzcIQR7SEU6dNujp/SgvhxhJOhIhI9gY4r0I3/TNtvVQwARWor9O9LPZWg==", 571 | "dev": true, 572 | "requires": { 573 | "@fimbul/bifrost": "^0.17.0", 574 | "tslib": "^1.7.1", 575 | "tsutils": "^2.29.0" 576 | } 577 | }, 578 | "tslint-eslint-rules": { 579 | "version": "5.4.0", 580 | "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz", 581 | "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==", 582 | "dev": true, 583 | "requires": { 584 | "doctrine": "0.7.2", 585 | "tslib": "1.9.0", 586 | "tsutils": "^3.0.0" 587 | }, 588 | "dependencies": { 589 | "tslib": { 590 | "version": "1.9.0", 591 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", 592 | "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", 593 | "dev": true 594 | }, 595 | "tsutils": { 596 | "version": "3.14.0", 597 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", 598 | "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", 599 | "dev": true, 600 | "requires": { 601 | "tslib": "^1.8.1" 602 | } 603 | } 604 | } 605 | }, 606 | "tslint-microsoft-contrib": { 607 | "version": "5.2.1", 608 | "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.2.1.tgz", 609 | "integrity": "sha512-PDYjvpo0gN9IfMULwKk0KpVOPMhU6cNoT9VwCOLeDl/QS8v8W2yspRpFFuUS7/c5EIH/n8ApMi8TxJAz1tfFUA==", 610 | "dev": true, 611 | "requires": { 612 | "tsutils": "^2.27.2 <2.29.0" 613 | }, 614 | "dependencies": { 615 | "tsutils": { 616 | "version": "2.28.0", 617 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.28.0.tgz", 618 | "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==", 619 | "dev": true, 620 | "requires": { 621 | "tslib": "^1.8.1" 622 | } 623 | } 624 | } 625 | }, 626 | "tsutils": { 627 | "version": "2.29.0", 628 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 629 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 630 | "dev": true, 631 | "requires": { 632 | "tslib": "^1.8.1" 633 | } 634 | }, 635 | "typescript": { 636 | "version": "3.6.2", 637 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", 638 | "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==" 639 | }, 640 | "util-deprecate": { 641 | "version": "1.0.2", 642 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 643 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 644 | }, 645 | "wrappy": { 646 | "version": "1.0.2", 647 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 648 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 649 | "dev": true 650 | } 651 | } 652 | } 653 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easy-vm", 3 | "version": "1.3.0", 4 | "description": "Run securely untrusted code with whitelisted Node modules", 5 | "main": "build/index", 6 | "types": "build/index.d.ts", 7 | "scripts": { 8 | "watch": "tsc --watch", 9 | "build": "tsc", 10 | "lint": "tslint \"src/**/*.ts*\"", 11 | "lint-fix": "prettier --write \"src/**/*.ts*\" && tslint \"src/**/*.ts*\" --fix", 12 | "prepublishOnly": "npm run build", 13 | "test": "npm run build" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/sentialx/easy-vm.git" 18 | }, 19 | "keywords": [ 20 | "vm", 21 | "nodejs" 22 | ], 23 | "author": "sentialx", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/sentialx/easy-vm/issues" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "homepage": "https://github.com/sentialx/easy-vm#readme", 32 | "devDependencies": { 33 | "@types/node": "12.7.4", 34 | "tslint": "5.19.0", 35 | "tslint-config-airbnb": "5.11.1", 36 | "tslint-config-prettier": "1.18.0", 37 | "prettier": "1.18.2" 38 | }, 39 | "dependencies": { 40 | "ts-loader": "6.0.4", 41 | "typescript": "3.6.2" 42 | } 43 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import EasyVM from './models/vm'; 2 | 3 | export = EasyVM; 4 | -------------------------------------------------------------------------------- /src/models/vm-options.ts: -------------------------------------------------------------------------------- 1 | import VMRequireOptions from './vm-require-options'; 2 | 3 | export default interface VMOptions { 4 | require?: VMRequireOptions | false; 5 | console?: boolean; 6 | sandbox?: object; 7 | timeout?: number; 8 | } // eslint-disable-line 9 | -------------------------------------------------------------------------------- /src/models/vm-require-options.ts: -------------------------------------------------------------------------------- 1 | export default interface VMRequireOptions { 2 | mock?: any; 3 | builtin?: string[]; 4 | } // eslint-disable-line 5 | -------------------------------------------------------------------------------- /src/models/vm.ts: -------------------------------------------------------------------------------- 1 | import * as vm from 'vm'; 2 | import VMOptions from './vm-options'; 3 | import VMRequireOptions from './vm-require-options'; 4 | 5 | const { Module } = require('module'); 6 | 7 | export default class { 8 | private options: VMOptions = { 9 | require: false, 10 | console: true, 11 | timeout: 0, 12 | }; 13 | 14 | public constructor(options: VMOptions) { 15 | this.options = {...this.options, ...options}; 16 | } 17 | 18 | public run(code: string, filename?: string) { 19 | const newModule = new Module(filename); 20 | newModule.filename = filename; 21 | newModule.paths = [filename]; 22 | newModule.loaded = true; 23 | 24 | const newModuleCopy = { ...newModule }; 25 | 26 | const context: any = { 27 | ...this.options.sandbox, 28 | module: newModuleCopy, 29 | exports: newModuleCopy.exports, 30 | }; 31 | 32 | if (this.options.console) { 33 | context.console = console; 34 | } 35 | 36 | if (this.options.require) { 37 | context.require = (id: string) => { 38 | if (id.startsWith('.')) { 39 | return newModule.require(id); 40 | } 41 | 42 | if (typeof this.options.require === 'object') { 43 | const req = this.options.require as VMRequireOptions; 44 | if (req.builtin[0] === '*') { 45 | if (req.mock[id]) return req.mock[id]; 46 | return newModule.require(id); 47 | } 48 | 49 | const mod = req.builtin.find(x => x === id); 50 | if (mod) { 51 | if (req.mock && req.mock[id]) return req.mock[id]; 52 | return newModule.require(id); 53 | } 54 | } 55 | return null; 56 | }; 57 | 58 | context.module.require = context.require; 59 | } 60 | 61 | const script = new vm.Script(code, { 62 | filename, 63 | }); 64 | 65 | return { 66 | result: script.runInNewContext(context, { timeout: this.options.timeout }), 67 | script, 68 | context, 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./build/", 4 | "baseUrl": "./src", 5 | "typeRoots": [ 6 | "./node_modules/@types" 7 | ], 8 | "noImplicitAny": true, 9 | "module": "commonjs", 10 | "target": "es2015", 11 | "sourceMap": true, 12 | "moduleResolution": "node", 13 | "esModuleInterop": true, 14 | "declaration": true, 15 | "types": [ 16 | "node" 17 | ] 18 | }, 19 | "include": [ 20 | "./src/**/*.ts" 21 | ], 22 | "exclude": [ 23 | "node_modules/**/*" 24 | ] 25 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint-config-airbnb"], 3 | "rules": { 4 | "no-increment-decrement": false, 5 | "max-line-length": false, 6 | "variable-name": [ 7 | true, 8 | "ban-keywords", 9 | "check-format", 10 | "allow-pascal-case", 11 | "allow-leading-underscore" 12 | ], 13 | "import-name": false, 14 | "ter-arrow-parens": false, 15 | "no-parameter-reassignment": false, 16 | "object-shorthand-properties-first": false, 17 | "semicolon": false, 18 | "align": false, 19 | "no-this-assignment": false 20 | } 21 | } 22 | --------------------------------------------------------------------------------