isolated-function 0.0.3 → 0.0.4

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "isolated-function",
3
3
  "description": "Runs untrusted code in a Node.js v8 sandbox.",
4
4
  "homepage": "https://github.com/Kikobeats/isolated-function",
5
- "version": "0.0.3",
5
+ "version": "0.0.4",
6
6
  "main": "src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js"
@@ -37,10 +37,8 @@
37
37
  "acorn-walk": "~8.3.3",
38
38
  "ensure-error": "~3.0.1",
39
39
  "esbuild": "~0.23.1",
40
- "process-stats": "~3.7.10",
41
40
  "serialize-error": "8",
42
- "tinyspawn": "~1.3.2",
43
- "v8-sandbox": "~3.2.12"
41
+ "tinyspawn": "~1.3.2"
44
42
  },
45
43
  "devDependencies": {
46
44
  "@commitlint/cli": "latest",
package/src/compile.js CHANGED
@@ -46,31 +46,37 @@ const detectDependencies = code => {
46
46
  return Array.from(dependencies)
47
47
  }
48
48
 
49
- module.exports = async snippet => {
50
- const tmp = await fs.mkdtemp(path.join(tmpdir(), 'compile-'))
51
- await fs.mkdir(tmp, { recursive: true })
49
+ const getTmp = async content => {
50
+ const cwd = await fs.mkdtemp(path.join(tmpdir(), 'compile-'))
51
+ await fs.mkdir(cwd, { recursive: true })
52
52
 
53
- const template = generateTemplate(snippet)
53
+ const filepath = path.join(cwd, 'index.js')
54
+ await fs.writeFile(filepath, content)
54
55
 
55
- const entryFile = path.join(tmp, 'index.js')
56
- await fs.writeFile(entryFile, template)
56
+ const cleanup = () => fs.rm(cwd, { recursive: true, force: true })
57
+ return { filepath, cwd, content, cleanup }
58
+ }
57
59
 
58
- const dependencies = detectDependencies(template)
59
- await $(packageManager.init, { cwd: tmp })
60
- await $(`${packageManager.install} ${dependencies.join(' ')}`, { cwd: tmp })
60
+ module.exports = async snippet => {
61
+ const tmp = await getTmp(generateTemplate(snippet))
62
+ const dependencies = detectDependencies(tmp.content)
63
+ await $(packageManager.init, { cwd: tmp.cwd })
64
+ await $(`${packageManager.install} ${dependencies.join(' ')}`, {
65
+ cwd: tmp.cwd
66
+ })
67
+
68
+ // return tmp
61
69
 
62
70
  const result = await esbuild.build({
63
- entryPoints: [entryFile],
71
+ entryPoints: [tmp.filepath],
64
72
  bundle: true,
73
+ // minify: true,
65
74
  write: false,
66
75
  platform: 'node'
67
76
  })
68
77
 
69
- const bundledCode = result.outputFiles[0].text
70
-
71
- await fs.rm(tmp, { recursive: true })
72
-
73
- return bundledCode
78
+ await tmp.cleanup()
79
+ return getTmp(result.outputFiles[0].text)
74
80
  }
75
81
 
76
82
  module.exports.detectDependencies = detectDependencies
package/src/index.js CHANGED
@@ -1,32 +1,38 @@
1
1
  'use strict'
2
2
 
3
- const { Sandbox } = require('v8-sandbox')
4
3
  const { deserializeError } = require('serialize-error')
4
+ const $ = require('tinyspawn')
5
5
 
6
6
  const compile = require('./compile')
7
7
 
8
- module.exports = (snippet, { timeout = 10000, globals = {} } = {}) => {
9
- if (typeof snippet !== 'function') {
10
- throw new TypeError('Expected a function')
8
+ class TimeoutError extends Error {
9
+ constructor (message) {
10
+ super(message)
11
+ this.name = 'TimeoutError'
11
12
  }
13
+ }
12
14
 
13
- const sandbox = new Sandbox({
14
- httpEnabled: false,
15
- timersEnabled: true,
16
- debug: true
17
- })
18
- const compiling = compile(snippet)
19
- const initializing = sandbox.initialize()
15
+ module.exports = (snippet, { timeout = 0 } = {}) => {
16
+ if (typeof snippet !== 'function') throw new TypeError('Expected a function')
17
+ const compilePromise = compile(snippet)
20
18
 
21
- return async (...args) => {
22
- const [code] = await Promise.all([compiling, initializing])
23
- const { error, value } = await sandbox.execute({
24
- code,
25
- timeout,
26
- globals: { ...globals, arguments: args }
27
- })
28
- await sandbox.shutdown()
29
- if (error) throw require('ensure-error')(deserializeError(error))
30
- return value
19
+ const fn = async (...args) => {
20
+ try {
21
+ const { filepath } = await compilePromise
22
+ const { stdout } = await $(`node ${filepath} ${JSON.stringify(args)}`, {
23
+ timeout,
24
+ killSignal: 'SIGKILL'
25
+ })
26
+ const { isFulfilled, value } = JSON.parse(stdout)
27
+ if (isFulfilled) return value
28
+ throw deserializeError(value)
29
+ } catch (error) {
30
+ if (error.killed) throw new TimeoutError('Execution timed out')
31
+ throw error
32
+ }
31
33
  }
34
+
35
+ const cleanup = async () => (await compilePromise).cleanup
36
+
37
+ return [fn, cleanup]
32
38
  }
@@ -2,37 +2,20 @@
2
2
 
3
3
  const SERIALIZE_ERROR = require('./serialize-error')
4
4
 
5
- const DISALLOW_INTERNALS = [
6
- '_dispatch',
7
- 'base64ToBuffer',
8
- 'bufferToBase64',
9
- 'define',
10
- 'defineAsync',
11
- 'dispatch',
12
- 'httpRequest',
13
- 'info',
14
- 'setResult'
15
- ]
16
-
17
5
  const generateTemplate = snippet => {
18
- const value = (() => {
19
- return `await (() => {
20
- let ${DISALLOW_INTERNALS.join(',')};
21
- globalThis = { clearTimeout, setTimeout }
22
- globalThis.global = globalThis
23
- return (${snippet.toString()})(...arguments)
24
- })()`
6
+ const template = `
7
+ const args = JSON.parse(process.argv[2])
8
+
9
+ ;(async () => {
10
+ try {
11
+ const value = await (${snippet.toString()})(...args)
12
+ console.log(JSON.stringify({ isFulfilled: true, value }))
13
+ } catch (error) {
14
+ console.log(JSON.stringify({ isFulfilled: false, value: ${SERIALIZE_ERROR}(error) }))
15
+ }
25
16
  })()
26
17
 
27
- const template = `;(async () => {
28
- try {
29
- setResult({
30
- value: ${value}
31
- })
32
- } catch(error) {
33
- setResult({ error: ${SERIALIZE_ERROR}(error) })
34
- }
35
- })()`
18
+ `
36
19
 
37
20
  return template
38
21
  }