Skip to content

Commit 27d5c52

Browse files
committed
sandoxing with support for middleware info
1 parent 1c93064 commit 27d5c52

6 files changed

Lines changed: 177 additions & 56 deletions

File tree

src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ const Comms = require('./comms')
22
const Config = require('./config')
33
const Party = require('./party')
44
const Service = require('./service')
5+
const Sandbox = require('./sandbox')
56

67
module.exports = {
78
Comms,
89
Config,
910
...Party,
10-
...Service
11+
...Service,
12+
...Sandbox
1113
}

src/sandbox/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
Sandbox: require('./sandbox'),
3+
SandboxError: require('./sandbox-error'),
4+
MiddlewareInfoSandbox: require('./middleware-info-sandbox')
5+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//const debug = require('debug')('dataparty.MiddlewareInfoSandbox')
2+
const Sandbox = require('./sandbox')
3+
4+
class MiddlewareInfoSandbox extends Sandbox {
5+
constructor(code){
6+
super(`
7+
8+
module.exports = async ()=>{
9+
10+
class ErrorError extends Error {
11+
constructor(msg){
12+
super()
13+
this.code = 'ErrorError'
14+
this.message = 'You did not throw an error object, always throw an Error object! - [' + msg + ']'
15+
}
16+
}
17+
18+
try{
19+
let Lib = ${code}
20+
21+
return {
22+
Name: Lib.Name,
23+
Type: Lib.Type,
24+
Description: Lib.Description,
25+
ConfigSchema: Lib.ConfigSchema
26+
}
27+
}
28+
catch(err){
29+
30+
if(!err || !err.stack){
31+
err = new ErrorError(err)
32+
}
33+
34+
throw err
35+
}
36+
37+
}
38+
`)
39+
40+
this.info = null
41+
}
42+
43+
async run(){
44+
45+
46+
this.info = await super.run()
47+
48+
return this.info
49+
}
50+
51+
}
52+
53+
module.exports = MiddlewareInfoSandbox

src/sandbox/sandbox-error.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
class SandboxError extends Error {
2+
constructor(err, accessor){
3+
super()
4+
this.message = err.message
5+
6+
7+
this.code = err.code || err.name || 'SandboxError'
8+
this.name = this.code
9+
this.stack = err.stack
10+
this.locations = VMError.filterStackForModuleLines(err.stack, accessor)
11+
}
12+
13+
static filterStackForModuleLines(stack, accessor){
14+
15+
let founds = []
16+
17+
if(!stack){
18+
return founds
19+
}
20+
21+
const prefix = '(vm.js:'
22+
stack.split('\n').map(line=>{
23+
24+
let idx = line.indexOf(prefix)
25+
26+
if(idx > -1){
27+
const found = {
28+
line: null,
29+
col: null,
30+
code: null
31+
}
32+
33+
let start = idx+prefix.length
34+
let end = line.indexOf(')')
35+
36+
const [l, c] = line.substr(start, end-start).split(':')
37+
38+
found.col = c
39+
found.line = l
40+
found.code = accessor.code.split('\n')[found.line-1]
41+
42+
founds.push(found)
43+
}
44+
})
45+
46+
return founds
47+
}
48+
}
49+
50+
module.exports = SandboxError

src/sandbox/sandbox.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const debug = require('debug')('dataparty.Sandbox')
2+
const {VM, NodeVM, VMScript} = require('vm2')
3+
4+
const SandboxError = require('./sandbox-error')
5+
6+
class Sandbox {
7+
constructor(code){
8+
debug('compiling code')
9+
this.code = code
10+
this.script = new VMScript(code)
11+
debug('compiled')
12+
}
13+
14+
async run(context, sandbox){
15+
debug('running')
16+
try{
17+
18+
let vm = new NodeVM({
19+
sandbox,
20+
require: {
21+
external: {
22+
modules: ['debug', '@dataparty/crypto', '@hapi/joi', '@hapi/hoek']
23+
},
24+
//builtin: ['*']
25+
}
26+
})
27+
28+
let fn = vm.run(this.script)
29+
const retVal = await fn(context)
30+
return retVal
31+
32+
} catch(err) {
33+
34+
debug('CodeVM.run - catch')
35+
debug('',err)
36+
throw new SandboxError(err,this)
37+
}
38+
}
39+
}
40+
41+
module.exports = Sandbox

test/test-service-compile.js

Lines changed: 25 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ const Path = require('path')
22
const debug = require('debug')('test.service-compile')
33
const Dataparty = require('../src')
44

5-
const {VM, NodeVM, VMScript} = require('vm2')
5+
//const {VM, NodeVM, VMScript} = require('vm2')
6+
7+
process.on('uncaughtException', (err) => {
8+
console.error('Asynchronous error caught.', err);
9+
})
610

711
class ExampleService extends Dataparty.IService {
812
constructor(opts){
@@ -13,72 +17,38 @@ class ExampleService extends Dataparty.IService {
1317

1418
}
1519

16-
class CodeAccessor {
17-
constructor(code){
18-
debug('code-accessor', code)
19-
this.script = new VMScript(code)
20-
debug('compiled')
21-
}
22-
23-
run(context, sandbox){
24-
debug('run')
25-
26-
27-
let vm = new NodeVM({
28-
sandbox,
29-
require: {
30-
external: {
31-
modules: ['debug', '@dataparty/crypto', '@hapi/joi', '@hapi/hoek']
32-
},
33-
//builtin: ['*']
34-
}
35-
})
36-
37-
debug('has run')
38-
let fn = vm.run(this.script)
39-
const retVal = fn(context)
40-
debug('retVal', retVal)
41-
debug('context', context)
42-
return retVal
43-
}
44-
45-
}
46-
47-
class MiddlewareInfoAccessor extends CodeAccessor {
48-
constructor(code){
49-
super(`
50-
51-
let lib = ${code}
52-
53-
module.exports = ()=>{
54-
55-
return {
56-
Name: lib.Name,
57-
Type: lib.Type,
58-
Description: lib.Description,
59-
ConfigSchema: lib.ConfigSchema
60-
}
61-
}
62-
`)
63-
}
64-
65-
}
6620

6721
async function main(){
6822

69-
console.log(Object.keys(Dataparty))
23+
debug(Object.keys(Dataparty))
7024

7125
const service = new ExampleService({ name: '@dataparty/example', version: '0.0.1' })
7226

7327
const build = await service.compile(Path.join(__dirname,'../dataparty'), false)
7428

7529
//debug(build.middleware.pre.decrypt)
7630

77-
let accessor = new MiddlewareInfoAccessor(build.middleware.pre.decrypt.code)
31+
let decryptInfo = new Dataparty.MiddlewareInfoSandbox(build.middleware.pre.decrypt.code)
32+
33+
try{
34+
await decryptInfo.run()
35+
}
36+
catch(err){
37+
debug('supressing error')
38+
debug('\tname\t',err.name)
39+
debug('\tcode\t',err.code)
40+
41+
debug('\tmsg\t',err.message)
7842

79-
console.log(accessor.run('derp'))
43+
debug('\tstack\t',err.stack)
44+
45+
debug('\tlocations\t',err.locations)
46+
}
8047

81-
console.log(build)
48+
debug('# Middleware #')
49+
debug('\t Name=', decryptInfo.info.Name)
50+
debug('\t Type="', decryptInfo.info.Type, '"')
51+
debug('\t Desc="', decryptInfo.info.Description, '"')
8252

8353
process.exit()
8454
}

0 commit comments

Comments
 (0)