Skip to content

Tasks in repository Sandboxes #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions JavaScript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@
// of a sample application to be executed in the sandboxed context by
// another pice of code from `framework.js`. Read README.md for tasks.

const fs = require('fs');
const net = require('net');
const o = new Map ([
[ ((field) => field)('field'), 'hello' ],
[ 'field2', new Object({ field1: 10, field2: '20' }) ],
[ (fn => fn)('fn'), new Function('a, b', 'return a + b') ],
[ (function arr(name){return name})('arr'), new Array(1,2,3) ],
[ ['boolean'], new Boolean(new Set() instanceof Object).valueOf() ],
//[ (async (n) => {return n})('async').then(console.log), new Promise(resolve => resolve()) ]
])

// Print from the global context of application module
console.log('From application global context');
console.dir({ fs, net }, { depth: 1 });
console.dir({ global }, { depth: 1 });
console.dir({ api }, { depth: 2 });
const fn = new Function('a,s', 'return a + s');

// require module fs and util
api.console.log(api.util.inspect(o));

api.console.log('From global context');
require('fs');
require('util');

// exported function
module.exports = () => {
// Print from the exported function context
console.log('From application exported function');
};
api.timers.setTimeout(() => api.console.log('From exported timeout'), 1000)
api.timers.setInterval(() => api.console.log('From exported timeout'), 2000)
}

// usage of timers
api.timers.setTimeout(() => {
api.console.log('From timer');
}, 1000)
115 changes: 62 additions & 53 deletions JavaScript/framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,76 @@
// appication runtime, load an application code and passes a sandbox into app
// as a global context and receives exported application interface

const PARSING_TIMEOUT = 1000;
const EXECUTION_TIMEOUT = 5000;

// The framework can require core libraries
const fs = require('fs');
const vm = require('vm');
const timers = require('timers');
const events = require('events');
global.api = {};
api.fs = require('fs');
api.vm = require('vm');
api.util = require('util');

function Req() {};
// #6
Req.prototype.fn = function (module) {
console.log('ModuleName: ' + module);
console.log('Time: ' + new Date());
require(module);
}
// #4
Req.prototype.wrapped = function (path, fn) {
const wrapped = item => {
console.log('ApplicationName: ' + path);
console.log('Time: ' + new Date());
fn(item);
};
return wrapped;
}
// #8
Req.prototype.count = function(f) {
console.log(f.length);
console.log(f.toString());
}

// Create a hash and turn it into the sandboxed context which will be
// the global context of an application
const context = {
module: {}, console,
require: name => {
if (name === 'fs') {
console.log('Module fs is restricted');
return null;
const runSandboxed = path => {
const context = {
module: {},
require: new Req().fn,
api: {
console: { log: new Req().wrapped(path, console.log) }, // #1
timers: { setTimeout, setInterval },
fs: api.fs,
util: api.util // #2
},
}
return require(name);
}
};

context.global = context;
const sandbox = vm.createContext(context);
context.global = context;
const sandbox = api.vm.createContext(context);
// Read an application source code from the file
api.fs.readFile(path, (err, src) => {
// We need to handle errors here

// Prepare lambda context injection
const api = { timers, events };
// Run an application in sandboxed context
const script = new api.vm.Script(src);
// #3
if (process.argv[2] === path || path === 'application.js') script.runInNewContext(sandbox);

// Read an application source code from the file
const fileName = './application.js';
fs.readFile(fileName, 'utf8', (err, src) => {
// We need to handle errors here
const exported = sandbox.module.exports;
console.log(exported);

// Wrap source to lambda, inject api
src = `api => { ${src} };`;
//count args of exported function and print input code
if (typeof exported === 'function') { new Req().count(exported); exported() }

// Run an application in sandboxed context
let script;
try {
script = new vm.Script(src, { timeout: PARSING_TIMEOUT });
} catch (e) {
console.dir(e);
console.log('Parsing timeout');
process.exit(1);
}
// print type of exported inside items, (instance of Map)
// console.log(exported)
// exported instanceof Map --- false
else if (new Map([]) instanceof Map) { // #7
for (const [key, val] of exported.entries()) {
console.log(key + ': ' + typeof val);
};
}

try {
const f = script.runInNewContext(sandbox, { timeout: EXECUTION_TIMEOUT });
f(api);
const exported = sandbox.module.exports;
console.dir({ exported });
} catch (e) {
console.dir(e);
console.log('Execution timeout');
process.exit(1);
}
// We can access a link to exported interface from sandbox.module.exports
// to execute, save to the cache, print to console, etc.

// We can access a link to exported interface from sandbox.module.exports
// to execute, save to the cache, print to console, etc.
});
})
}

process.on('uncaughtException', err => {
console.log('Unhandled exception: ' + err);
});
runSandboxed('application.js');