ethereum/mist

View on GitHub
modules/preloader/browser.js

Summary

Maintainability
C
7 hrs
Test Coverage
/**
@module preloader browser
*/
const _ = require('underscore');
require('./include/common')('browser');
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');

// set navigator.language
Object.defineProperty(navigator, 'language', {
  get() {
    return ipcRenderer.sendSync('backendAction_getLanguage');
  }
});

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

const isValidJsonRpc = function(message) {
  return !!(
    Object.prototype.hasOwnProperty.call(message, 'method') ||
    Object.prototype.hasOwnProperty.call(message, 'id') ||
    Object.prototype.hasOwnProperty.call(message, 'params') ||
    Object.prototype.hasOwnProperty.call(message, 'jsonrpc')
  );
};

const sanatizeJsonRpc = function(message) {
  // sanitize
  return {
    jsonrpc: message.jsonrpc,
    id: message.id,
    method: message.method,
    params: message.params
  };
};

// Wait for post messages
window.addEventListener('message', function message(event) {
  let 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') {
    let messageIsArray = _.isArray(data.message);

    // only accept valid JSON rpc requests
    if (messageIsArray) {
      for (let i = 0; i < data.message.length; i++) {
        if (isValidJsonRpc(data.message[i])) {
          data.message[i] = sanatizeJsonRpc(data.message[i]);
        } else {
          return;
        }
      }
    } else {
      if (isValidJsonRpc(data.message)) {
        data.message = sanatizeJsonRpc(data.message);
      } else {
        return;
      }
    }

    // make sure we only send allowed properties
    ipcRenderer.send('ipcProvider-write', JSON.stringify(data.message));

    // 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);
    }
  }
});

const 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.join(__dirname, '/injected/BigNumber.js'))
  .toString();
const eventEmitter3 = fs
  .readFileSync(path.join(__dirname, '/injected/EventEmitter3.js'))
  .toString();
let mistAPI = fs
  .readFileSync(path.join(__dirname, '/injected/mistAPI.js'))
  .toString();
const ethereumProvider = fs
  .readFileSync(path.join(__dirname, '/injected/EthereumProvider.js'))
  .toString();

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]
  );

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');