Skip to content
This repository has been archived by the owner on Sep 5, 2020. It is now read-only.

Commit

Permalink
Merging Preloader isolation (#2087)
Browse files Browse the repository at this point in the history
  • Loading branch information
evertonfraga committed Apr 19, 2017
2 parents 616d5c7 + f90d7d4 commit 2dfab6a
Show file tree
Hide file tree
Showing 14 changed files with 1,495 additions and 683 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ To run mist in development you need:
- [Node.js](https://nodejs.org) `v6.x` (use the prefered installation method for your OS)
- [Meteor](https://www.meteor.com/install) javascript app framework
- [Yarn](https://yarnpkg.com/) package manager
- [Electron](http://electron.atom.io/) `v1.3.13` cross platform desktop app framework
- [Electron](http://electron.atom.io/) `v1.6.2` cross platform desktop app framework
- [Gulp](http://gulpjs.com/) build and automation system

Install the later ones via:

$ curl https://install.meteor.com/ | sh
$ curl -o- -L https://yarnpkg.com/install.sh | bash
$ yarn global add electron@1.3.13
$ yarn global add electron@1.6.2
$ yarn global add gulp

### Initialisation
Expand Down
2 changes: 1 addition & 1 deletion interface/client/templates/views/webview.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{{#if $eq _id "tests"}}
<webview src="file://{{dirname}}/tests/mocha-in-browser/runner.html" useragent="{{useragent}}" data-id="{{_id}}" preload="{{preloaderFile}}" autosize="on"></webview>
{{else}}
<webview src="{{checkedUrl}}" useragent="{{useragent}}" data-id="{{_id}}" preload="{{preloaderFile}}" autosize="on"></webview>
<webview src="{{checkedUrl}}" useragent="{{useragent}}" data-id="{{_id}}" preload="{{preloaderFile}}" webpreferences="contextIsolation=yes" autosize="on"></webview>
{{/if}}
</div>
</template>
1 change: 0 additions & 1 deletion modules/ipc/ipcProviderBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class IpcProviderBackend {
log.debug(`Destroy socket connection due to event: ${ev}, id=${ownerId}`);

socket.destroy().finally(() => {

if (!owner.isDestroyed()) { owner.send(`ipcProvider-${ev}`, JSON.stringify(data)); }
});

Expand Down
128 changes: 111 additions & 17 deletions modules/preloader/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,125 @@
@module preloader browser
*/
require('./include/common')('browser');
require('./include/ethereumProvider.js');
const { ipcRenderer } = require('electron');
const { ipcRenderer, webFrame, remote } = require('electron');
const mist = require('./include/mistAPI.js');
require('./include/getFavicon.js');
require('./include/getMetaTags.js');
require('./include/setBasePath')('interface');
const packageJson = require('./../../package.json');
const fs = remote.require('fs');
const path = remote.require('path');

// notifiy the tab to store the webview id
ipcRenderer.sendToHost('setWebviewId');

// destroy the old socket
ipcRenderer.send('ipcProvider-destroy');
// Wait for post messages
window.addEventListener('message', function message(event) {
var data;
try {
data = JSON.parse(event.data);
} catch(e){
data = event.data;
}


if (typeof data !== 'object') {
return;
}

// EthereumProvider: connect
if (data.type === 'create') {
ipcRenderer.send('ipcProvider-create');

// EthereumProvider: write
} else if (data.type === 'write') {
// only accept valid JSON rpc requests
if(!Object.prototype.hasOwnProperty.call(data.message, 'method') ||
!Object.prototype.hasOwnProperty.call(data.message, 'id') ||
!Object.prototype.hasOwnProperty.call(data.message, 'params') ||
!Object.prototype.hasOwnProperty.call(data.message, 'jsonrpc')) {
return;
}

// make sure we only send allowed properties
ipcRenderer.send('ipcProvider-write', JSON.stringify({
jsonrpc: data.message.jsonrpc,
id: data.message.id,
method: data.message.method,
params: data.message.params
}));

// mistAPI
} else if (/^mistAPI_[a-z]/i.test(data.type)) {

if (data.type === 'mistAPI_requestAccount') {
ipcRenderer.send(data.type, data.message);
} else {
ipcRenderer.sendToHost(data.type, data.message);
}
}


});

// Security
process.on('loaded', function () {
Object.freeze(window.JSON);
// Object.freeze(window.Function);
// Object.freeze(window.Function.prototype);
// Object.freeze(window.Array);
// Object.freeze(window.Array.prototype);
var postMessage = function(payload) {
if(typeof payload === 'object') {
payload = JSON.stringify(payload);
}

window.postMessage(payload, (!location.origin || location.origin === "null" ) ? '*' : location.origin);
};

// custom Events
['uiAction_windowMessage', 'mistAPI_callMenuFunction'].forEach(function (type) {
ipcRenderer.on(type, function onIpcRenderer(e, result) {

// this type needs special packaging
if(type === 'uiAction_windowMessage') {
result = {
type: arguments[1],
error: arguments[2],
value: arguments[3]
};
}

postMessage({
type: type,
message: result
});
});
});

// add IPCbackend events
['data', 'error', 'end', 'timeout', 'connect'].forEach(function (type) {
ipcRenderer.on(`ipcProvider-`+ type, function onIpcRenderer(e, result) {
postMessage({
type: type,
message: JSON.parse(result)
});
});
});


// load ethereumProvider
const bignumber = fs.readFileSync(path.resolve('./modules/preloader/injected/BigNumber.js')).toString();
const eventEmitter3 = fs.readFileSync(path.resolve('./modules/preloader/injected/EventEmitter3.js')).toString();
let mistAPI = fs.readFileSync(path.resolve('./modules/preloader/injected/mistAPI.js')).toString();
const ethereumProvider = fs.readFileSync(path.resolve('./modules/preloader/injected/EthereumProvider.js')).toString();

window.mist = mist();
mistAPI = mistAPI.replace('__version__', packageJson.version)
.replace('__license__', packageJson.license)
.replace('__platform__', process.platform)
.replace('__solidityVersion__', String(packageJson.dependencies.solc).match(/\d+\.\d+\.\d+/)[0]);

// prevent overwriting the Dapps Web3
delete global.Web3;
delete window.Web3;
webFrame.executeJavaScript(
mistAPI +
bignumber +
eventEmitter3 +
ethereumProvider
);


// notifiy the tab to store the webview id
ipcRenderer.sendToHost('setWebviewId');

// destroy the old socket
ipcRenderer.send('ipcProvider-destroy');
1 change: 1 addition & 0 deletions modules/preloader/include/mistAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ module.exports = () => {
});

ipcRenderer.on('uiAction_windowMessage', (e, type, error, value) => {
console.log('uiAction_windowMessage',type, error, value);
if (mist.callbacks[type]) {
mist.callbacks[type].forEach((cb) => {
cb(error, value);
Expand Down
9 changes: 9 additions & 0 deletions modules/preloader/injected/BigNumber.js

Large diffs are not rendered by default.

170 changes: 170 additions & 0 deletions modules/preloader/injected/EthereumProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@

(function () {
var EventEmitter = window.EventEmitter;

var postMessage = function(payload) {
if(typeof payload === 'object') {
payload = JSON.stringify(payload);
}

window.postMessage(payload, (!location.origin || location.origin === "null" ) ? '*' : location.origin);
};

// on events are: "connect", "data", "error", "end", "timeout"
// "data" will get notifications

function EthereumProvider() {
var _this = this;
// Call constructor of superclass to initialize superclass-derived members.
EventEmitter.call(this);

this.responseCallbacks = {};

// fire the connect
this.connect();
this._reconnectCheck();



// Wait for response messages
window.addEventListener('message', function(event) {
var data;
try {
data = JSON.parse(event.data);
} catch(e){
data = event.data;
}


if(typeof data !== 'object' || (data.message && !Object.prototype.hasOwnProperty.call(data.message, 'jsonrpc'))) {
return;
}

if (data.type === 'data') {

var id = null;
var result = data.message;

// get the id which matches the returned id
if(typeof result === 'object' && result.forEach && isFinite(result.length)) {
result.forEach(function(load){
if(_this.responseCallbacks[load.id])
id = load.id;
});
} else {
id = result.id;
}

// notification
if(!id && result.method && result.method.indexOf('_subscription') !== -1) {
_this.listeners('data').forEach(function(callback){
if(typeof callback === 'function')
callback(null, result);
});

// fire the callback
} else if(_this.responseCallbacks[id]) {
_this.responseCallbacks[id](null, result);
delete _this.responseCallbacks[id];
}

// make all other events listenable
} else if(data.type) {
_this.listeners(data.type).forEach(function(callback){
if(typeof callback === 'function')
callback(null, data.message);
});
}
});
}

EthereumProvider.prototype = Object.create(EventEmitter.prototype);
EthereumProvider.prototype.constructor = EthereumProvider;

/**
Get the adds a callback to the responseCallbacks object,
which will be called if a response matching the response Id will arrive.
@method _addResponseCallback
*/
EthereumProvider.prototype._addResponseCallback = function(payload, callback) {
var id = payload.id || payload[0].id;
var method = payload.method || payload[0].method;

if (typeof callback !== 'function') {
throw new Error('No callback given, sync calls are not possible anymore in Mist. Please use only async calls.');
}

this.responseCallbacks[id] = callback;
this.responseCallbacks[id].method = method;
};


/**
Will watch for connection drops and tries to reconnect.
@method _reconnectCheck
*/
EthereumProvider.prototype._reconnectCheck = function() {
var _this = this;
var reconnectIntervalId;

this.on('end', function () {
reconnectIntervalId = setInterval(function () {
_this.connect();
}, 500);
});

this.on('connect', function () {
clearInterval(reconnectIntervalId);
});
};



/**
Will try to make a connection
@method connect
*/
EthereumProvider.prototype.connect = function(payload, callback) {
postMessage({
type: 'create'
});
};

/**
Sends the request
@method send
@param {Object} payload example: {id: 1, jsonrpc: '2.0', 'method': 'eth_someMethod', params: []}
@param {Function} callback the callback to call
*/
EthereumProvider.prototype.send = function send(payload, callback) {

this._addResponseCallback(payload, callback);
postMessage({
type: 'write',
message: payload
}, this.origin);
};




delete window.EventEmitter;
window.ethereumProvider = new EthereumProvider();


// For backwards compatibility of web3.currentProvider;
EthereumProvider.prototype.sendSync = function () {
return {jsonrpc: '2.0', error: {"code": -32603, message: 'Sync calls are not supported in Mist.'}};
};
EthereumProvider.prototype.sendAsync = EthereumProvider.prototype.send;
EthereumProvider.prototype.isConnected = function () {
return true;
};
window.web3 = {
currentProvider: new EthereumProvider()
};
})();
Loading

0 comments on commit 2dfab6a

Please sign in to comment.