From 5bc2602bfd5c1909759b582a9067c888b9313588 Mon Sep 17 00:00:00 2001 From: Bagus Aji Santoso Date: Mon, 4 Apr 2016 13:13:06 +0700 Subject: [PATCH] Remove jailed and all references to it --- public/js/lib/jailed/_JailedSite.js | 432 ----------- public/js/lib/jailed/_frame.html | 1 - public/js/lib/jailed/_frame.js | 56 -- public/js/lib/jailed/_pluginCore.js | 95 --- public/js/lib/jailed/_pluginNode.js | 267 ------- public/js/lib/jailed/_pluginWeb.js | 96 --- public/js/lib/jailed/jailed.js | 780 -------------------- server/views/partials/challenge-footer.jade | 1 - 8 files changed, 1728 deletions(-) delete mode 100644 public/js/lib/jailed/_JailedSite.js delete mode 100644 public/js/lib/jailed/_frame.html delete mode 100644 public/js/lib/jailed/_frame.js delete mode 100644 public/js/lib/jailed/_pluginCore.js delete mode 100644 public/js/lib/jailed/_pluginNode.js delete mode 100644 public/js/lib/jailed/_pluginWeb.js delete mode 100644 public/js/lib/jailed/jailed.js diff --git a/public/js/lib/jailed/_JailedSite.js b/public/js/lib/jailed/_JailedSite.js deleted file mode 100644 index 54fba0fdbd..0000000000 --- a/public/js/lib/jailed/_JailedSite.js +++ /dev/null @@ -1,432 +0,0 @@ - -/** - * Contains the JailedSite object used both by the application - * site, and by each plugin - */ - -(function(){ - - /** - * JailedSite object represents a single site in the - * communication protocol between the application and the plugin - * - * @param {Object} connection a special object allowing to send - * and receive messages from the opposite site (basically it - * should only provide send() and onMessage() methods) - */ - JailedSite = function(connection) { - this._interface = {}; - this._remote = null; - this._remoteUpdateHandler = function(){}; - this._getInterfaceHandler = function(){}; - this._interfaceSetAsRemoteHandler = function(){}; - this._disconnectHandler = function(){}; - this._store = new ReferenceStore; - - var me = this; - this._connection = connection; - this._connection.onMessage( - function(data){ me._processMessage(data); } - ); - - this._connection.onDisconnect( - function(m){ - me._disconnectHandler(m); - } - ); - } - - - /** - * Set a handler to be called when the remote site updates its - * interface - * - * @param {Function} handler - */ - JailedSite.prototype.onRemoteUpdate = function(handler) { - this._remoteUpdateHandler = handler; - } - - - /** - * Set a handler to be called when received a responce from the - * remote site reporting that the previously provided interface - * has been succesfully set as remote for that site - * - * @param {Function} handler - */ - JailedSite.prototype.onInterfaceSetAsRemote = function(handler) { - this._interfaceSetAsRemoteHandler = handler; - } - - - /** - * Set a handler to be called when the remote site requests to - * (re)send the interface. Used to detect an initialzation - * completion without sending additional request, since in fact - * 'getInterface' request is only sent by application at the last - * step of the plugin initialization - * - * @param {Function} handler - */ - JailedSite.prototype.onGetInterface = function(handler) { - this._getInterfaceHandler = handler; - } - - - /** - * @returns {Object} set of remote interface methods - */ - JailedSite.prototype.getRemote = function() { - return this._remote; - } - - - /** - * Sets the interface of this site making it available to the - * remote site by sending a message with a set of methods names - * - * @param {Object} _interface to set - */ - JailedSite.prototype.setInterface = function(_interface) { - this._interface = _interface; - this._sendInterface(); - } - - - /** - * Sends the actual interface to the remote site upon it was - * updated or by a special request of the remote site - */ - JailedSite.prototype._sendInterface = function() { - var names = []; - for (var name in this._interface) { - if (this._interface.hasOwnProperty(name)) { - names.push(name); - } - } - - this._connection.send({type:'setInterface', api: names}); - } - - - /** - * Handles a message from the remote site - */ - JailedSite.prototype._processMessage = function(data) { - switch(data.type) { - case 'method': - var method = this._interface[data.name]; - var args = this._unwrap(data.args); - method.apply(null, args); - break; - case 'callback': - var method = this._store.fetch(data.id)[data.num]; - var args = this._unwrap(data.args); - method.apply(null, args); - break; - case 'setInterface': - this._setRemote(data.api); - break; - case 'getInterface': - this._sendInterface(); - this._getInterfaceHandler(); - break; - case 'interfaceSetAsRemote': - this._interfaceSetAsRemoteHandler(); - break; - case 'disconnect': - this._disconnectHandler(); - this._connection.disconnect(); - break; - } - } - - - /** - * Sends a requests to the remote site asking it to provide its - * current interface - */ - JailedSite.prototype.requestRemote = function() { - this._connection.send({type:'getInterface'}); - } - - - /** - * Sets the new remote interface provided by the other site - * - * @param {Array} names list of function names - */ - JailedSite.prototype._setRemote = function(names) { - this._remote = {}; - var i, name; - for (i = 0; i < names.length; i++) { - name = names[i]; - this._remote[name] = this._genRemoteMethod(name); - } - - this._remoteUpdateHandler(); - this._reportRemoteSet(); - } - - - /** - * Generates the wrapped function corresponding to a single remote - * method. When the generated function is called, it will send the - * corresponding message to the remote site asking it to execute - * the particular method of its interface - * - * @param {String} name of the remote method - * - * @returns {Function} wrapped remote method - */ - JailedSite.prototype._genRemoteMethod = function(name) { - var me = this; - var remoteMethod = function() { - me._connection.send({ - type: 'method', - name: name, - args: me._wrap(arguments) - }); - }; - - return remoteMethod; - } - - - /** - * Sends a responce reporting that interface just provided by the - * remote site was sucessfully set by this site as remote - */ - JailedSite.prototype._reportRemoteSet = function() { - this._connection.send({type:'interfaceSetAsRemote'}); - } - - - /** - * Prepares the provided set of remote method arguments for - * sending to the remote site, replaces all the callbacks with - * identifiers - * - * @param {Array} args to wrap - * - * @returns {Array} wrapped arguments - */ - JailedSite.prototype._wrap = function(args) { - var wrapped = []; - var callbacks = {}; - var callbacksPresent = false; - for (var i = 0; i < args.length; i++) { - if (typeof args[i] == 'function') { - callbacks[i] = args[i]; - wrapped[i] = {type: 'callback', num : i}; - callbacksPresent = true; - } else { - wrapped[i] = {type: 'argument', value : args[i]}; - } - } - - var result = {args: wrapped}; - - if (callbacksPresent) { - result.callbackId = this._store.put(callbacks); - } - - return result; - } - - - /** - * Unwraps the set of arguments delivered from the remote site, - * replaces all callback identifiers with a function which will - * initiate sending that callback identifier back to other site - * - * @param {Object} args to unwrap - * - * @returns {Array} unwrapped args - */ - JailedSite.prototype._unwrap = function(args) { - var called = false; - - // wraps each callback so that the only one could be called - var once = function(cb) { - return function() { - if (!called) { - called = true; - cb.apply(this, arguments); - } else { - var msg = - 'A callback from this set has already been executed'; - throw new Error(msg); - } - }; - } - - var result = []; - var i, arg, cb, me = this; - for (i = 0; i < args.args.length; i++) { - arg = args.args[i]; - if (arg.type == 'argument') { - result.push(arg.value); - } else { - cb = once( - this._genRemoteCallback(args.callbackId, i) - ); - result.push(cb); - } - } - - return result; - } - - - /** - * Generates the wrapped function corresponding to a single remote - * callback. When the generated function is called, it will send - * the corresponding message to the remote site asking it to - * execute the particular callback previously saved during a call - * by the remote site a method from the interface of this site - * - * @param {Number} id of the remote callback to execute - * @param {Number} argNum argument index of the callback - * - * @returns {Function} wrapped remote callback - */ - JailedSite.prototype._genRemoteCallback = function(id, argNum) { - var me = this; - var remoteCallback = function() { - me._connection.send({ - type : 'callback', - id : id, - num : argNum, - args : me._wrap(arguments) - }); - }; - - return remoteCallback; - } - - - /** - * Sends the notification message and breaks the connection - */ - JailedSite.prototype.disconnect = function() { - this._connection.send({type: 'disconnect'}); - this._connection.disconnect(); - } - - - /** - * Set a handler to be called when received a disconnect message - * from the remote site - * - * @param {Function} handler - */ - JailedSite.prototype.onDisconnect = function(handler) { - this._disconnectHandler = handler; - } - - - - - /** - * ReferenceStore is a special object which stores other objects - * and provides the references (number) instead. This reference - * may then be sent over a json-based communication channel (IPC - * to another Node.js process or a message to the Worker). Other - * site may then provide the reference in the responce message - * implying the given object should be activated. - * - * Primary usage for the ReferenceStore is a storage for the - * callbacks, which therefore makes it possible to initiate a - * callback execution by the opposite site (which normally cannot - * directly execute functions over the communication channel). - * - * Each stored object can only be fetched once and is not - * available for the second time. Each stored object must be - * fetched, since otherwise it will remain stored forever and - * consume memory. - * - * Stored object indeces are simply the numbers, which are however - * released along with the objects, and are later reused again (in - * order to postpone the overflow, which should not likely happen, - * but anyway). - */ - var ReferenceStore = function() { - this._store = {}; // stored object - this._indices = [0]; // smallest available indices - } - - - /** - * @function _genId() generates the new reference id - * - * @returns {Number} smallest available id and reserves it - */ - ReferenceStore.prototype._genId = function() { - var id; - if (this._indices.length == 1) { - id = this._indices[0]++; - } else { - id = this._indices.shift(); - } - - return id; - } - - - /** - * Releases the given reference id so that it will be available by - * another object stored - * - * @param {Number} id to release - */ - ReferenceStore.prototype._releaseId = function(id) { - for (var i = 0; i < this._indices.length; i++) { - if (id < this._indices[i]) { - this._indices.splice(i, 0, id); - break; - } - } - - // cleaning-up the sequence tail - for (i = this._indices.length-1; i >= 0; i--) { - if (this._indices[i]-1 == this._indices[i-1]) { - this._indices.pop(); - } else { - break; - } - } - } - - - /** - * Stores the given object and returns the refernce id instead - * - * @param {Object} obj to store - * - * @returns {Number} reference id of the stored object - */ - ReferenceStore.prototype.put = function(obj) { - var id = this._genId(); - this._store[id] = obj; - return id; - } - - - /** - * Retrieves previously stored object and releases its reference - * - * @param {Number} id of an object to retrieve - */ - ReferenceStore.prototype.fetch = function(id) { - var obj = this._store[id]; - this._store[id] = null; - delete this._store[id]; - this._releaseId(id); - return obj; - } - - -})(); - diff --git a/public/js/lib/jailed/_frame.html b/public/js/lib/jailed/_frame.html deleted file mode 100644 index 68b300d6e3..0000000000 --- a/public/js/lib/jailed/_frame.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/public/js/lib/jailed/_frame.js b/public/js/lib/jailed/_frame.js deleted file mode 100644 index f9e28d641e..0000000000 --- a/public/js/lib/jailed/_frame.js +++ /dev/null @@ -1,56 +0,0 @@ - -/** - * Contains the code executed in the sandboxed frame under web-browser - * - * Creates a Web-Worker inside the frame, sets up the communication - * between the worker and the parent window - */ - - -var scripts = document.getElementsByTagName('script'); -var __jailed__path__ = scripts[scripts.length-1].src - .split('?')[0] - .split('/') - .slice(0, -1) - .join('/') + '/'; - -// creating worker as a blob enables import of local files -var blobCode = [ - ' self.addEventListener("message", function(m){ ', - ' if (m.data.type == "initImport") { ', - ' importScripts(m.data.url); ', - ' self.postMessage({type: "initialized"}); ', - ' } ', - ' }); ' -].join('\n'); - -var blobUrl; -try { - blobUrl = new Blob([blobCode], {type: 'application/javascript'}); -} catch (e) { - window.BlobBuilder = window.BlobBuilder - || window.WebKitBlobBuilder - || window.MozBlobBuilder; - blobUrl = new BlobBuilder(); - blobUrl.append(blobCode); - blobUrl = blobUrl.getBlob(); -} - -var worker = new Worker(URL.createObjectURL(blobUrl)); - -// telling worker to load _pluginWeb.js (see blob code above) -worker.postMessage({ - type: 'initImport', - url: __jailed__path__ + '_pluginWeb.js' -}); - - -// forwarding messages between the worker and parent window -worker.addEventListener('message', function(m) { - parent.postMessage(m.data, '*'); -}); - -window.addEventListener('message', function(m) { - worker.postMessage(m.data); -}); - diff --git a/public/js/lib/jailed/_pluginCore.js b/public/js/lib/jailed/_pluginCore.js deleted file mode 100644 index 184113a124..0000000000 --- a/public/js/lib/jailed/_pluginCore.js +++ /dev/null @@ -1,95 +0,0 @@ - -/** - * Core plugin script loaded into the plugin process/thread. - * - * Initializes the plugin-site API global methods. - */ - -(function(){ - - // localize - var site = new JailedSite(connection); - delete JailedSite; - delete connection; - - site.onGetInterface(function(){ - launchConnected(); - }); - - site.onRemoteUpdate(function(){ - application.remote = site.getRemote(); - }); - - - - /** - * Simplified clone of Whenable instance (the object can not be - * placed into a shared script, because the main library needs it - * before the additional scripts may load) - */ - var connected = false; - var connectedHandlers = []; - - var launchConnected = function() { - if (!connected) { - connected = true; - - var handler; - while(handler = connectedHandlers.pop()) { - handler(); - } - } - } - - var checkHandler = function(handler){ - var type = typeof handler; - if (type != 'function') { - var msg = - 'A function may only be subsribed to the event, ' - + type - + ' was provided instead' - throw new Error(msg); - } - - return handler; - } - - - /** - * Sets a function executed after the connection to the - * application is estaplished, and the initial interface-exchange - * messaging is completed - * - * @param {Function} handler to be called upon initialization - */ - application.whenConnected = function(handler) { - handler = checkHandler(handler); - if (connected) { - handler(); - } else { - connectedHandlers.push(handler); - } - } - - - /** - * Sets the plugin interface available to the application - * - * @param {Object} _interface to set - */ - application.setInterface = function(_interface) { - site.setInterface(_interface); - } - - - - /** - * Disconnects the plugin from the application (sending - * notification message) and destroys itself - */ - application.disconnect = function(_interface) { - site.disconnect(); - } - -})(); - diff --git a/public/js/lib/jailed/_pluginNode.js b/public/js/lib/jailed/_pluginNode.js deleted file mode 100644 index ee9d49469b..0000000000 --- a/public/js/lib/jailed/_pluginNode.js +++ /dev/null @@ -1,267 +0,0 @@ - -/** - * 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; - diff --git a/public/js/lib/jailed/_pluginWeb.js b/public/js/lib/jailed/_pluginWeb.js deleted file mode 100644 index bb250de36c..0000000000 --- a/public/js/lib/jailed/_pluginWeb.js +++ /dev/null @@ -1,96 +0,0 @@ - -/** - * Contains the routines loaded by the plugin Worker under web-browser. - * - * Initializes the web environment version of the platform-dependent - * connection object for the plugin site - */ - -self.application = {}; -self.connection = {}; - - -(function(){ - - /** - * Event lisener for the plugin message - */ - self.addEventListener('message', function(e){ - var m = e.data.data; - switch (m.type) { - case 'import': - case 'importJailed': // already jailed in the Worker - importScript(m.url); - break; - case 'execute': - execute(m.code); - break; - case 'message': - conn._messageHandler(m.data); - break; - } - }); - - - /** - * Loads and executes the JavaScript file with the given url - * - * @param {String} url to load - */ - var importScript = function(url) { - var error = null; - try { - importScripts(url); - } catch (e) { - error = e; - } - - if (error) { - self.postMessage({type: 'importFailure', url: url}); - throw error; - } else { - self.postMessage({type: 'importSuccess', url: url}); - } - - } - - - /** - * Executes the given code in a jailed environment. For web - * implementation, we're already jailed in the worker, so simply - * eval() - * - * @param {String} code code to execute - */ - var execute = function(code) { - try { - eval(code); - } catch (e) { - self.postMessage({type: 'executeFailure'}); - throw e; - } - - self.postMessage({type: 'executeSuccess'}); - } - - - /** - * Connection object provided to the JailedSite constructor, - * plugin site implementation for the web-based environment. - * Global will be then cleared to prevent exposure into the - * Worker, so we put this local connection object into a closure - */ - var conn = { - disconnect: function(){ self.close(); }, - send: function(data) { - self.postMessage({type: 'message', data: data}); - }, - onMessage: function(h){ conn._messageHandler = h; }, - _messageHandler: function(){}, - onDisconnect: function() {} - }; - - connection = conn; - -})(); - diff --git a/public/js/lib/jailed/jailed.js b/public/js/lib/jailed/jailed.js deleted file mode 100644 index e4525068ea..0000000000 --- a/public/js/lib/jailed/jailed.js +++ /dev/null @@ -1,780 +0,0 @@ -/** - * @fileoverview Jailed - safe yet flexible sandbox - * @version 0.2.0 - * - * @license MIT, see http://github.com/asvd/jailed - * Copyright (c) 2014 asvd - * - * Main library script, the only one to be loaded by a developer into - * the application. Other scrips shipped along will be loaded by the - * library either here (application site), or into the plugin site - * (Worker/child process): - * - * _JailedSite.js loaded into both applicaiton and plugin sites - * _frame.html sandboxed frame (web) - * _frame.js sandboxed frame code (web) - * _pluginWeb.js platform-dependent plugin routines (web) - * _pluginNode.js platform-dependent plugin routines (Node.js) - * _pluginCore.js common plugin site protocol implementation - */ - - -var __jailed__path__; -if (typeof window == 'undefined') { - // Node.js - __jailed__path__ = __dirname + '/'; -} else { - // web - var scripts = document.getElementsByTagName('script'); - __jailed__path__ = scripts[scripts.length-1].src - .split('?')[0] - .split('/') - .slice(0, -1) - .join('/')+'/'; -} - - -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.jailed = {})); - } -}(this, function (exports) { - var isNode = typeof window == 'undefined'; - - - /** - * A special kind of event: - * - which can only be emitted once; - * - executes a set of subscribed handlers upon emission; - * - if a handler is subscribed after the event was emitted, it - * will be invoked immideately. - * - * Used for the events which only happen once (or do not happen at - * all) during a single plugin lifecycle - connect, disconnect and - * connection failure - */ - var Whenable = function() { - this._emitted = false; - this._handlers = []; - } - - - /** - * Emits the Whenable event, calls all the handlers already - * subscribed, switches the object to the 'emitted' state (when - * all future subscibed listeners will be immideately issued - * instead of being stored) - */ - Whenable.prototype.emit = function(){ - if (!this._emitted) { - this._emitted = true; - - var handler; - while(handler = this._handlers.pop()) { - setTimeout(handler,0); - } - } - } - - - /** - * Saves the provided function as a handler for the Whenable - * event. This handler will then be called upon the event emission - * (if it has not been emitted yet), or will be scheduled for - * immediate issue (if the event has already been emmitted before) - * - * @param {Function} handler to subscribe for the event - */ - Whenable.prototype.whenEmitted = function(handler){ - handler = this._checkHandler(handler); - if (this._emitted) { - setTimeout(handler, 0); - } else { - this._handlers.push(handler); - } - } - - - /** - * Checks if the provided object is suitable for being subscribed - * to the event (= is a function), throws an exception if not - * - * @param {Object} obj to check for being subscribable - * - * @throws {Exception} if object is not suitable for subscription - * - * @returns {Object} the provided object if yes - */ - Whenable.prototype._checkHandler = function(handler){ - var type = typeof handler; - if (type != 'function') { - var msg = - 'A function may only be subsribed to the event, ' - + type - + ' was provided instead' - throw new Error(msg); - } - - return handler; - } - - - - /** - * Initializes the library site for Node.js environment (loads - * _JailedSite.js) - */ - var initNode = function() { - require('./_JailedSite.js'); - } - - - /** - * Initializes the library site for web environment (loads - * _JailedSite.js) - */ - var platformInit; - var initWeb = function() { - // loads additional script to the application environment - var load = function(path, cb) { - var script = document.createElement('script'); - script.src = path; - - var clear = function() { - script.onload = null; - script.onerror = null; - script.onreadystatechange = null; - script.parentNode.removeChild(script); - } - - var success = function() { - clear(); - cb(); - } - - script.onerror = clear; - script.onload = success; - script.onreadystatechange = function() { - var state = script.readyState; - if (state==='loaded' || state==='complete') { - success(); - } - } - - document.body.appendChild(script); - } - - platformInit = new Whenable; - var origOnload = window.onload || function(){}; - - window.onload = function(){ - origOnload(); - load( - __jailed__path__+'_JailedSite.js', - function(){ platformInit.emit(); } - ); - } - } - - - var BasicConnection; - - /** - * Creates the platform-dependent BasicConnection object in the - * Node.js environment - */ - var basicConnectionNode = function() { - var childProcess = require('child_process'); - - /** - * Platform-dependent implementation of the BasicConnection - * object, initializes the plugin site and provides the basic - * messaging-based connection with it - * - * For Node.js the plugin is created as a forked process - */ - BasicConnection = function() { - this._disconnected = false; - this._messageHandler = function(){}; - this._disconnectHandler = function(){}; - this._process = childProcess.fork( - __jailed__path__+'_pluginNode.js' - ); - - var me = this; - this._process.on('message', function(m){ - me._messageHandler(m); - }); - - this._process.on('exit', function(m){ - me._disconnected = true; - me._disconnectHandler(m); - }); - } - - - /** - * Sets-up the handler to be called upon the BasicConnection - * initialization is completed. - * - * For Node.js the connection is fully initialized within the - * constructor, so simply calls the provided handler. - * - * @param {Function} handler to be called upon connection init - */ - BasicConnection.prototype.whenInit = function(handler) { - handler(); - } - - - /** - * Sends a message to the plugin site - * - * @param {Object} data to send - */ - BasicConnection.prototype.send = function(data) { - if (!this._disconnected) { - this._process.send(data); - } - } - - - /** - * Adds a handler for a message received from the plugin site - * - * @param {Function} handler to call upon a message - */ - BasicConnection.prototype.onMessage = function(handler) { - this._messageHandler = function(data) { - // broken stack would break the IPC in Node.js - try { - handler(data); - } catch (e) { - console.error(); - console.error(e.stack); - } - } - } - - - /** - * Adds a handler for the event of plugin disconnection - * (= plugin process exit) - * - * @param {Function} handler to call upon a disconnect - */ - BasicConnection.prototype.onDisconnect = function(handler) { - this._disconnectHandler = handler; - } - - - /** - * Disconnects the plugin (= kills the forked process) - */ - BasicConnection.prototype.disconnect = function() { - this._process.kill('SIGKILL'); - this._disconnected = true; - } - - } - - - /** - * Creates the platform-dependent BasicConnection object in the - * web-browser environment - */ - var basicConnectionWeb = function() { - var perm = ['allow-scripts']; - - if (__jailed__path__.substr(0,7).toLowerCase() == 'file://') { - // local instance requires extra permission - perm.push('allow-same-origin'); - } - - // frame element to be cloned - var sample = document.createElement('iframe'); - sample.src = __jailed__path__ + '_frame.html'; - sample.sandbox = perm.join(' '); - sample.style.display = 'none'; - - - /** - * Platform-dependent implementation of the BasicConnection - * object, initializes the plugin site and provides the basic - * messaging-based connection with it - * - * For the web-browser environment, the plugin is created as a - * Worker in a sandbaxed frame - */ - BasicConnection = function() { - this._init = new Whenable; - this._disconnected = false; - - var me = this; - platformInit.whenEmitted(function() { - if (!me._disconnected) { - me._frame = sample.cloneNode(false); - document.body.appendChild(me._frame); - - window.addEventListener('message', function (e) { - if (e.origin === "null" && - e.source === me._frame.contentWindow) { - if (e.data.type == 'initialized') { - me._init.emit(); - } else { - me._messageHandler(e.data); - } - } - }); - } - }); - } - - - /** - * Sets-up the handler to be called upon the BasicConnection - * initialization is completed. - * - * For the web-browser environment, the handler is issued when - * the plugin worker successfully imported and executed the - * _pluginWeb.js, and replied to the application site with the - * initImprotSuccess message. - * - * @param {Function} handler to be called upon connection init - */ - BasicConnection.prototype.whenInit = function(handler) { - this._init.whenEmitted(handler); - } - - - /** - * Sends a message to the plugin site - * - * @param {Object} data to send - */ - BasicConnection.prototype.send = function(data) { - this._frame.contentWindow.postMessage( - {type: 'message', data: data}, '*' - ); - } - - - /** - * Adds a handler for a message received from the plugin site - * - * @param {Function} handler to call upon a message - */ - BasicConnection.prototype.onMessage = function(handler) { - this._messageHandler = handler; - } - - - /** - * Adds a handler for the event of plugin disconnection - * (not used in case of Worker) - * - * @param {Function} handler to call upon a disconnect - */ - BasicConnection.prototype.onDisconnect = function(){}; - - - /** - * Disconnects the plugin (= kills the frame) - */ - BasicConnection.prototype.disconnect = function() { - if (!this._disconnected) { - this._disconnected = true; - if (typeof this._frame != 'undefined') { - this._frame.parentNode.removeChild(this._frame); - } // otherwise farme is not yet created - } - } - - } - - - if (isNode) { - initNode(); - basicConnectionNode(); - } else { - initWeb(); - basicConnectionWeb(); - } - - - - /** - * Application-site Connection object constructon, reuses the - * platform-dependent BasicConnection declared above in order to - * communicate with the plugin environment, implements the - * application-site protocol of the interraction: provides some - * methods for loading scripts and executing the given code in the - * plugin - */ - var Connection = function(){ - this._platformConnection = new BasicConnection; - - this._importCallbacks = {}; - this._executeSCb = function(){}; - this._executeFCb = function(){}; - this._messageHandler = function(){}; - - var me = this; - this.whenInit = function(cb){ - me._platformConnection.whenInit(cb); - }; - - this._platformConnection.onMessage(function(m) { - switch(m.type) { - case 'message': - me._messageHandler(m.data); - break; - case 'importSuccess': - me._handleImportSuccess(m.url); - break; - case 'importFailure': - me._handleImportFailure(m.url); - break; - case 'executeSuccess': - me._executeSCb(); - break; - case 'executeFailure': - me._executeFCb(); - break; - } - }); - } - - - /** - * Tells the plugin to load a script with the given path, and to - * execute it. Callbacks executed upon the corresponding responce - * message from the plugin site - * - * @param {String} path of a script to load - * @param {Function} sCb to call upon success - * @param {Function} fCb to call upon failure - */ - Connection.prototype.importScript = function(path, sCb, fCb) { - var f = function(){}; - this._importCallbacks[path] = {sCb: sCb||f, fCb: fCb||f}; - this._platformConnection.send({type: 'import', url: path}); - } - - - /** - * Tells the plugin to load a script with the given path, and to - * execute it in the JAILED environment. Callbacks executed upon - * the corresponding responce message from the plugin site - * - * @param {String} path of a script to load - * @param {Function} sCb to call upon success - * @param {Function} fCb to call upon failure - */ - Connection.prototype.importJailedScript = function(path, sCb, fCb) { - var f = function(){}; - this._importCallbacks[path] = {sCb: sCb||f, fCb: fCb||f}; - this._platformConnection.send({type: 'importJailed', url: path}); - } - - - /** - * Sends the code to the plugin site in order to have it executed - * in the JAILED enviroment. Assuming the execution may only be - * requested once by the Plugin object, which means a single set - * of callbacks is enough (unlike importing additional scripts) - * - * @param {String} code code to execute - * @param {Function} sCb to call upon success - * @param {Function} fCb to call upon failure - */ - Connection.prototype.execute = function(code, sCb, fCb) { - this._executeSCb = sCb||function(){}; - this._executeFCb = fCb||function(){}; - this._platformConnection.send({type: 'execute', code: code}); - } - - - /** - * Adds a handler for a message received from the plugin site - * - * @param {Function} handler to call upon a message - */ - Connection.prototype.onMessage = function(handler) { - this._messageHandler = handler; - } - - - /** - * Adds a handler for a disconnect message received from the - * plugin site - * - * @param {Function} handler to call upon disconnect - */ - Connection.prototype.onDisconnect = function(handler) { - this._platformConnection.onDisconnect(handler); - } - - - /** - * Sends a message to the plugin - * - * @param {Object} data of the message to send - */ - Connection.prototype.send = function(data) { - this._platformConnection.send({ - type: 'message', - data: data - }); - } - - - /** - * Handles import succeeded message from the plugin - * - * @param {String} url of a script loaded by the plugin - */ - Connection.prototype._handleImportSuccess = function(url) { - var sCb = this._importCallbacks[url].sCb; - this._importCallbacks[url] = null; - delete this._importCallbacks[url]; - sCb(); - } - - - /** - * Handles import failure message from the plugin - * - * @param {String} url of a script loaded by the plugin - */ - Connection.prototype._handleImportFailure = function(url) { - var fCb = this._importCallbacks[url].fCb; - this._importCallbacks[url] = null; - delete this._importCallbacks[url]; - fCb(); - } - - - /** - * Disconnects the plugin when it is not needed anymore - */ - Connection.prototype.disconnect = function() { - this._platformConnection.disconnect(); - } - - - - - /** - * Plugin constructor, represents a plugin initialized by a script - * with the given path - * - * @param {String} url of a plugin source - * @param {Object} _interface to provide for the plugin - */ - var Plugin = function(url, _interface) { - this._path = url; - this._initialInterface = _interface||{}; - this._connect(); - } - - - /** - * DynamicPlugin constructor, represents a plugin initialized by a - * string containing the code to be executed - * - * @param {String} code of the plugin - * @param {Object} _interface to provide to the plugin - */ - var DynamicPlugin = function(code, _interface) { - this._code = code; - this._initialInterface = _interface||{}; - this._connect(); - } - - - /** - * Creates the connection to the plugin site - */ - DynamicPlugin.prototype._connect = - Plugin.prototype._connect = function() { - this.remote = null; - - this._connect = new Whenable; - this._fail = new Whenable; - this._disconnect = new Whenable; - - var me = this; - - // binded failure callback - this._fCb = function(){ - me._fail.emit(); - me.disconnect(); - } - - this._connection = new Connection; - this._connection.whenInit(function(){ - me._init(); - }); - } - - - /** - * Creates the Site object for the plugin, and then loads the - * common routines (_JailedSite.js) - */ - DynamicPlugin.prototype._init = - Plugin.prototype._init = function() { - this._site = new JailedSite(this._connection); - - var me = this; - this._site.onDisconnect(function() { - me._disconnect.emit(); - }); - - var sCb = function() { - me._loadCore(); - } - - this._connection.importScript( - __jailed__path__+'_JailedSite.js', sCb, this._fCb - ); - } - - - /** - * Loads the core scirpt into the plugin - */ - DynamicPlugin.prototype._loadCore = - Plugin.prototype._loadCore = function() { - var me = this; - var sCb = function() { - me._sendInterface(); - } - - this._connection.importScript( - __jailed__path__+'_pluginCore.js', sCb, this._fCb - ); - } - - - /** - * Sends to the remote site a signature of the interface provided - * upon the Plugin creation - */ - DynamicPlugin.prototype._sendInterface = - Plugin.prototype._sendInterface = function() { - var me = this; - this._site.onInterfaceSetAsRemote(function() { - if (!me._connected) { - me._loadPlugin(); - } - }); - - this._site.setInterface(this._initialInterface); - } - - - /** - * Loads the plugin body (loads the plugin url in case of the - * Plugin) - */ - Plugin.prototype._loadPlugin = function() { - var me = this; - var sCb = function() { - me._requestRemote(); - } - - this._connection.importJailedScript(this._path, sCb, this._fCb); - } - - - /** - * Loads the plugin body (executes the code in case of the - * DynamicPlugin) - */ - DynamicPlugin.prototype._loadPlugin = function() { - var me = this; - var sCb = function() { - me._requestRemote(); - } - - this._connection.execute(this._code, sCb, this._fCb); - } - - - /** - * Requests the remote interface from the plugin (which was - * probably set by the plugin during its initialization), emits - * the connect event when done, then the plugin is fully usable - * (meaning both the plugin and the application can use the - * interfaces provided to each other) - */ - DynamicPlugin.prototype._requestRemote = - Plugin.prototype._requestRemote = function() { - var me = this; - this._site.onRemoteUpdate(function(){ - me.remote = me._site.getRemote(); - me._connect.emit(); - }); - - this._site.requestRemote(); - } - - - /** - * Disconnects the plugin immideately - */ - DynamicPlugin.prototype.disconnect = - Plugin.prototype.disconnect = function() { - this._connection.disconnect(); - this._disconnect.emit(); - } - - - /** - * Saves the provided function as a handler for the connection - * failure Whenable event - * - * @param {Function} handler to be issued upon disconnect - */ - DynamicPlugin.prototype.whenFailed = - Plugin.prototype.whenFailed = function(handler) { - this._fail.whenEmitted(handler); - } - - - /** - * Saves the provided function as a handler for the connection - * success Whenable event - * - * @param {Function} handler to be issued upon connection - */ - DynamicPlugin.prototype.whenConnected = - Plugin.prototype.whenConnected = function(handler) { - this._connect.whenEmitted(handler); - } - - - /** - * Saves the provided function as a handler for the connection - * failure Whenable event - * - * @param {Function} handler to be issued upon connection failure - */ - DynamicPlugin.prototype.whenDisconnected = - Plugin.prototype.whenDisconnected = function(handler) { - this._disconnect.whenEmitted(handler); - } - - - - exports.Plugin = Plugin; - exports.DynamicPlugin = DynamicPlugin; - -})); - diff --git a/server/views/partials/challenge-footer.jade b/server/views/partials/challenge-footer.jade index 732c9dadb6..2112eae1ba 100644 --- a/server/views/partials/challenge-footer.jade +++ b/server/views/partials/challenge-footer.jade @@ -1,4 +1,3 @@ -script(type='text/javascript', src='/js/lib/jailed/jailed.js') script(src=rev('/js', 'vendor-challenges.js')) script(src=rev('/js', 'commonFramework.js')) script.