268 lines
5.8 KiB
JavaScript
268 lines
5.8 KiB
JavaScript
|
|
/**
|
|
* Contains the routines loaded by the plugin process under Node.js
|
|
*
|
|
* Initializes the Node.js environment version of the
|
|
* platform-dependent connection object for the plugin site
|
|
*/
|
|
|
|
application = {};
|
|
connection = {};
|
|
|
|
|
|
/**
|
|
* Prints error message and its stack
|
|
*
|
|
* @param {Object} msg stack provided by error.stack or a message
|
|
*/
|
|
var printError = function(msg) {
|
|
console.error();
|
|
console.error(msg);
|
|
}
|
|
|
|
|
|
/**
|
|
* Event lisener for the plugin message
|
|
*/
|
|
process.on('message', function(m) {
|
|
switch(m.type){
|
|
case 'import':
|
|
importScript(m.url);
|
|
break;
|
|
case 'importJailed':
|
|
importScriptJailed(m.url);
|
|
break;
|
|
case 'execute':
|
|
execute(m.code);
|
|
break;
|
|
case 'message':
|
|
// unhandled exception would break the IPC channel
|
|
try {
|
|
conn._messageHandler(m.data);
|
|
} catch(e) {
|
|
printError(e.stack);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
|
|
|
|
/**
|
|
* Checks if the given path is remote
|
|
*
|
|
* @param {String} path to check
|
|
* @returns {Boolean} true if path is remote
|
|
*/
|
|
var isRemote = function(path) {
|
|
return (path.substr(0,7).toLowerCase() == 'http://' ||
|
|
path.substr(0,8).toLowerCase() == 'https://');
|
|
}
|
|
|
|
|
|
/**
|
|
* Loads and executes the JavaScript file with the given url
|
|
*
|
|
* @param {String} url of the script to load
|
|
*/
|
|
var importScript = function(url) {
|
|
var sCb = function() {
|
|
process.send({type: 'importSuccess', url: url});
|
|
}
|
|
|
|
var fCb = function() {
|
|
process.send({type: 'importFailure', url: url});
|
|
}
|
|
|
|
var run = function(code) {
|
|
executeNormal(code, url, sCb, fCb);
|
|
}
|
|
|
|
if (isRemote(url)) {
|
|
loadRemote(url, run, fCb);
|
|
} else {
|
|
try {
|
|
run(loadLocal(url));
|
|
} catch(e) {
|
|
printError(e.stack);
|
|
fCb();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Loads and executes the JavaScript file with the given url in a
|
|
* jailed environment
|
|
*
|
|
* @param {String} url of the script to load
|
|
*/
|
|
var importScriptJailed = function(url) {
|
|
var sCb = function() {
|
|
process.send({type: 'importSuccess', url: url});
|
|
}
|
|
|
|
var fCb = function() {
|
|
process.send({type: 'importFailure', url: url});
|
|
}
|
|
|
|
var run = function(code) {
|
|
executeJailed(code, url, sCb, fCb);
|
|
}
|
|
|
|
if (isRemote(url)) {
|
|
loadRemote(url, run, fCb);
|
|
} else {
|
|
try {
|
|
run(loadLocal(url));
|
|
} catch (e) {
|
|
printError(e.stack);
|
|
fCb();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Executes the given code in the jailed environment, sends the
|
|
* corresponding message to the application site when succeeded/failed
|
|
*
|
|
* @param {String} code to execute
|
|
*/
|
|
var execute = function(code) {
|
|
var sCb = function() {
|
|
process.send({type: 'executeSuccess'});
|
|
}
|
|
|
|
var fCb = function() {
|
|
process.send({type: 'executeFailure'});
|
|
}
|
|
|
|
executeJailed(code, 'DYNAMIC PLUGIN', sCb, fCb);
|
|
}
|
|
|
|
|
|
/**
|
|
* Executes the given code in the current environment / scope, runs
|
|
* the corresponding callback when done
|
|
*
|
|
* @param {String} code to execute
|
|
* @param {String} url of the script (for displaying the stack)
|
|
* @param {Function} sCb
|
|
* @param {Function} fCb
|
|
*/
|
|
var executeNormal = function(code, url, sCb, fCb) {
|
|
var err = null;
|
|
try {
|
|
require('vm').runInThisContext(code, url);
|
|
sCb();
|
|
} catch (e) {
|
|
printError(e.stack);
|
|
fCb();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Executes the given code in a jailed environment, runs the
|
|
* corresponding callback when done
|
|
*
|
|
* @param {String} code to execute
|
|
* @param {String} url of the script (for displaying the stack)
|
|
* @param {Function} sCb
|
|
* @param {Function} fCb
|
|
*/
|
|
var executeJailed = function(code, url, sCb, fCb) {
|
|
var vm = require('vm');
|
|
var sandbox = {};
|
|
var expose = [
|
|
'application',
|
|
'setTimeout',
|
|
'setInterval',
|
|
'clearTimeout',
|
|
'clearInterval'
|
|
];
|
|
|
|
for (var i = 0; i < expose.length; i++) {
|
|
sandbox[expose[i]] = global[expose[i]];
|
|
}
|
|
|
|
code = '"use strict";\n'+code;
|
|
try {
|
|
vm.runInNewContext(code, vm.createContext(sandbox), url);
|
|
sCb();
|
|
} catch (e) {
|
|
printError(e.stack);
|
|
fCb();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Loads local file and
|
|
*
|
|
* @param {String} path of the file to read
|
|
*
|
|
* @returns {String} file contents
|
|
*/
|
|
var loadLocal = function(path) {
|
|
return require("fs").readFileSync(path).toString();
|
|
}
|
|
|
|
|
|
/**
|
|
* Downloads the script by remote url and provides its content as a
|
|
* string to the callback
|
|
*
|
|
* @param {String} url of the remote module to load
|
|
* @param {Function} sCb success callback
|
|
* @param {Function} fCb failure callback
|
|
*/
|
|
var loadRemote = function(url, sCb, fCb) {
|
|
var receive = function(res) {
|
|
if (res.statusCode != 200) {
|
|
var msg = 'Failed to load ' + url + '\n' +
|
|
'HTTP responce status code: ' + res.statusCode;
|
|
printError(msg);
|
|
fCb();
|
|
} else {
|
|
var content = '';
|
|
res.on('end', function(){ sCb(content); });
|
|
res.on(
|
|
'readable',
|
|
function() {
|
|
var chunk = res.read();
|
|
content += chunk.toString();
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
try {
|
|
require('http').get(url, receive).on('error', fCb);
|
|
} catch (e) {
|
|
printError(e.stack);
|
|
fCb();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Connection object provided to the SandboxedSite constructor, plugin
|
|
* site implementation for the Node.js environment
|
|
*/
|
|
var conn = {
|
|
disconnect: function(){ process.exit(); },
|
|
send: function(data) {
|
|
process.send({type: 'message', data: data});
|
|
},
|
|
onMessage: function(h){ conn._messageHandler = h; },
|
|
_messageHandler: function(){},
|
|
onDisconnect: function() {}
|
|
};
|
|
|
|
connection = conn;
|
|
|