From 6ce119d1fbf458fa93c63198da7e5bff3045d955 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 20 Aug 2018 15:39:03 -0700 Subject: Move inpage-provider and port-stream outside With the creation of the [metamask-extension-provider](https://github.com/MetaMask/metamask-extension-provider) we have our first non-core module that is dependent on the inpage-provider and port-stream. To reduce the size of its dependencies, I have moved the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider) into its own module, as well as [extension-port-stream](https://github.com/MetaMask/extension-port-stream). This allows them to be more easily depended & iterated on by external projects. --- app/scripts/background.js | 2 +- app/scripts/contentscript.js | 2 +- app/scripts/inpage.js | 2 +- app/scripts/lib/createErrorMiddleware.js | 67 ----------------- app/scripts/lib/inpage-provider.js | 125 ------------------------------- app/scripts/lib/port-stream.js | 80 -------------------- app/scripts/ui.js | 2 +- package-lock.json | 85 +++++++++++++++++++-- package.json | 6 +- 9 files changed, 87 insertions(+), 284 deletions(-) delete mode 100644 app/scripts/lib/createErrorMiddleware.js delete mode 100644 app/scripts/lib/inpage-provider.js delete mode 100644 app/scripts/lib/port-stream.js diff --git a/app/scripts/background.js b/app/scripts/background.js index c7395c810..d4d87e0d5 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -15,7 +15,7 @@ const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') const Migrator = require('./lib/migrator/') const migrations = require('./migrations/') -const PortStream = require('./lib/port-stream.js') +const PortStream = require('extension-port-stream') const createStreamSink = require('./lib/createStreamSink') const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index e0a2b0061..6eee1987a 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -5,7 +5,7 @@ const LocalMessageDuplexStream = require('post-message-stream') const PongStream = require('ping-pong-stream/pong') const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') -const PortStream = require('./lib/port-stream.js') +const PortStream = require('extension-port-stream') const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 7dd7fda02..1a170c617 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -4,7 +4,7 @@ require('web3/dist/web3.min.js') const log = require('loglevel') const LocalMessageDuplexStream = require('post-message-stream') const setupDappAutoReload = require('./lib/auto-reload.js') -const MetamaskInpageProvider = require('./lib/inpage-provider.js') +const MetamaskInpageProvider = require('metamask-inpage-provider') restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') diff --git a/app/scripts/lib/createErrorMiddleware.js b/app/scripts/lib/createErrorMiddleware.js deleted file mode 100644 index 7f6a4bd73..000000000 --- a/app/scripts/lib/createErrorMiddleware.js +++ /dev/null @@ -1,67 +0,0 @@ -const log = require('loglevel') - -/** - * JSON-RPC error object - * - * @typedef {Object} RpcError - * @property {number} code - Indicates the error type that occurred - * @property {Object} [data] - Contains additional information about the error - * @property {string} [message] - Short description of the error - */ - -/** - * Middleware configuration object - * - * @typedef {Object} MiddlewareConfig - * @property {boolean} [override] - Use RPC_ERRORS message in place of provider message - */ - -/** - * Map of standard and non-standard RPC error codes to messages - */ -const RPC_ERRORS = { - 1: 'An unauthorized action was attempted.', - 2: 'A disallowed action was attempted.', - 3: 'An execution error occurred.', - [-32600]: 'The JSON sent is not a valid Request object.', - [-32601]: 'The method does not exist / is not available.', - [-32602]: 'Invalid method parameter(s).', - [-32603]: 'Internal JSON-RPC error.', - [-32700]: 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.', - internal: 'Internal server error.', - unknown: 'Unknown JSON-RPC error.', -} - -/** - * Modifies a JSON-RPC error object in-place to add a human-readable message, - * optionally overriding any provider-supplied message - * - * @param {RpcError} error - JSON-RPC error object - * @param {boolean} override - Use RPC_ERRORS message in place of provider message - */ -function sanitizeRPCError (error, override) { - if (error.message && !override) { return error } - const message = error.code > -31099 && error.code < -32100 ? RPC_ERRORS.internal : RPC_ERRORS[error.code] - error.message = message || RPC_ERRORS.unknown -} - -/** - * json-rpc-engine middleware that both logs standard and non-standard error - * messages and ends middleware stack traversal if an error is encountered - * - * @param {MiddlewareConfig} [config={override:true}] - Middleware configuration - * @returns {Function} json-rpc-engine middleware function - */ -function createErrorMiddleware ({ override = true } = {}) { - return (req, res, next) => { - next(done => { - const { error } = res - if (!error) { return done() } - sanitizeRPCError(error) - log.error(`MetaMask - RPC Error: ${error.message}`, error) - done() - }) - } -} - -module.exports = createErrorMiddleware diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js deleted file mode 100644 index 6ef511453..000000000 --- a/app/scripts/lib/inpage-provider.js +++ /dev/null @@ -1,125 +0,0 @@ -const pump = require('pump') -const RpcEngine = require('json-rpc-engine') -const createErrorMiddleware = require('./createErrorMiddleware') -const createIdRemapMiddleware = require('json-rpc-engine/src/idRemapMiddleware') -const createStreamMiddleware = require('json-rpc-middleware-stream') -const LocalStorageStore = require('obs-store') -const asStream = require('obs-store/lib/asStream') -const ObjectMultiplex = require('obj-multiplex') - -module.exports = MetamaskInpageProvider - -function MetamaskInpageProvider (connectionStream) { - const self = this - - // setup connectionStream multiplexing - const mux = self.mux = new ObjectMultiplex() - pump( - connectionStream, - mux, - connectionStream, - (err) => logStreamDisconnectWarning('MetaMask', err) - ) - - // subscribe to metamask public config (one-way) - self.publicConfigStore = new LocalStorageStore({ storageKey: 'MetaMask-Config' }) - - pump( - mux.createStream('publicConfig'), - asStream(self.publicConfigStore), - (err) => logStreamDisconnectWarning('MetaMask PublicConfigStore', err) - ) - - // ignore phishing warning message (handled elsewhere) - mux.ignoreStream('phishing') - - // connect to async provider - const streamMiddleware = createStreamMiddleware() - pump( - streamMiddleware.stream, - mux.createStream('provider'), - streamMiddleware.stream, - (err) => logStreamDisconnectWarning('MetaMask RpcProvider', err) - ) - - // handle sendAsync requests via dapp-side rpc engine - const rpcEngine = new RpcEngine() - rpcEngine.push(createIdRemapMiddleware()) - rpcEngine.push(createErrorMiddleware()) - rpcEngine.push(streamMiddleware) - self.rpcEngine = rpcEngine -} - -// handle sendAsync requests via asyncProvider -// also remap ids inbound and outbound -MetamaskInpageProvider.prototype.sendAsync = function (payload, cb) { - const self = this - - if (payload.method === 'eth_signTypedData') { - console.warn('MetaMask: This experimental version of eth_signTypedData will be deprecated in the next release in favor of the standard as defined in EIP-712. See https://git.io/fNzPl for more information on the new standard.') - } - - self.rpcEngine.handle(payload, cb) -} - - -MetamaskInpageProvider.prototype.send = function (payload) { - const self = this - - let selectedAddress - let result = null - switch (payload.method) { - - case 'eth_accounts': - // read from localStorage - selectedAddress = self.publicConfigStore.getState().selectedAddress - result = selectedAddress ? [selectedAddress] : [] - break - - case 'eth_coinbase': - // read from localStorage - selectedAddress = self.publicConfigStore.getState().selectedAddress - result = selectedAddress || null - break - - case 'eth_uninstallFilter': - self.sendAsync(payload, noop) - result = true - break - - case 'net_version': - const networkVersion = self.publicConfigStore.getState().networkVersion - result = networkVersion || null - break - - // throw not-supported Error - default: - var link = 'https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#dizzy-all-async---think-of-metamask-as-a-light-client' - var message = `The MetaMask Web3 object does not support synchronous methods like ${payload.method} without a callback parameter. See ${link} for details.` - throw new Error(message) - - } - - // return the result - return { - id: payload.id, - jsonrpc: payload.jsonrpc, - result: result, - } -} - -MetamaskInpageProvider.prototype.isConnected = function () { - return true -} - -MetamaskInpageProvider.prototype.isMetaMask = true - -// util - -function logStreamDisconnectWarning (remoteLabel, err) { - let warningMsg = `MetamaskInpageProvider - lost connection to ${remoteLabel}` - if (err) warningMsg += '\n' + err.stack - console.warn(warningMsg) -} - -function noop () {} diff --git a/app/scripts/lib/port-stream.js b/app/scripts/lib/port-stream.js deleted file mode 100644 index fd65d94f3..000000000 --- a/app/scripts/lib/port-stream.js +++ /dev/null @@ -1,80 +0,0 @@ -const Duplex = require('readable-stream').Duplex -const inherits = require('util').inherits -const noop = function () {} - -module.exports = PortDuplexStream - -inherits(PortDuplexStream, Duplex) - -/** - * Creates a stream that's both readable and writable. - * The stream supports arbitrary objects. - * - * @class - * @param {Object} port Remote Port object - */ -function PortDuplexStream (port) { - Duplex.call(this, { - objectMode: true, - }) - this._port = port - port.onMessage.addListener(this._onMessage.bind(this)) - port.onDisconnect.addListener(this._onDisconnect.bind(this)) -} - -/** - * Callback triggered when a message is received from - * the remote Port associated with this Stream. - * - * @private - * @param {Object} msg - Payload from the onMessage listener of Port - */ -PortDuplexStream.prototype._onMessage = function (msg) { - if (Buffer.isBuffer(msg)) { - delete msg._isBuffer - var data = new Buffer(msg) - this.push(data) - } else { - this.push(msg) - } -} - -/** - * Callback triggered when the remote Port - * associated with this Stream disconnects. - * - * @private - */ -PortDuplexStream.prototype._onDisconnect = function () { - this.destroy() -} - -/** - * Explicitly sets read operations to a no-op - */ -PortDuplexStream.prototype._read = noop - - -/** - * Called internally when data should be written to - * this writable stream. - * - * @private - * @param {*} msg Arbitrary object to write - * @param {string} encoding Encoding to use when writing payload - * @param {Function} cb Called when writing is complete or an error occurs - */ -PortDuplexStream.prototype._write = function (msg, encoding, cb) { - try { - if (Buffer.isBuffer(msg)) { - var data = msg.toJSON() - data._isBuffer = true - this._port.postMessage(data) - } else { - this._port.postMessage(msg) - } - } catch (err) { - return cb(new Error('PortDuplexStream - disconnected')) - } - cb() -} diff --git a/app/scripts/ui.js b/app/scripts/ui.js index da100f928..98a036338 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -2,7 +2,7 @@ const injectCss = require('inject-css') const OldMetaMaskUiCss = require('../../old-ui/css') const NewMetaMaskUiCss = require('../../ui/css') const startPopup = require('./popup-core') -const PortStream = require('./lib/port-stream.js') +const PortStream = require('extension-port-stream') const { getEnvironmentType } = require('./lib/util') const { ENVIRONMENT_TYPE_NOTIFICATION } = require('./lib/enums') const extension = require('extensionizer') diff --git a/package-lock.json b/package-lock.json index ec0192500..b4ec81080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8568,12 +8568,13 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -8612,12 +8613,13 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -9841,6 +9843,52 @@ "extensionizer": "^1.0.0" } }, + "extension-port-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-1.0.0.tgz", + "integrity": "sha512-FsFr64yr6ituPdaGP6Io5recGFWVjJoDYt7asz2AvPkYqGN9c923nmEtyHH+413066bjGcQZaF8w5wn9HbNXiQ==", + "requires": { + "readable-stream": "^2.3.6", + "util": "^0.11.0" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.0.tgz", + "integrity": "sha512-5n12uMzKCjvB2HPFHnbQSjaqAa98L5iIXmHrZCLavuZVe0qe/SJGbDGWlpaHk5lnBkWRDO+dRu1/PgmUYKPPTw==", + "requires": { + "inherits": "2.0.3" + } + } + } + }, "extensionizer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/extensionizer/-/extensionizer-1.0.1.tgz", @@ -18731,6 +18779,26 @@ } } }, + "metamask-inpage-provider": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/metamask-inpage-provider/-/metamask-inpage-provider-1.0.0.tgz", + "integrity": "sha512-8ouTHzBuMb5DlsJstb3ikeA53zKk01ebcXEy3vHzg48MBO8sqHyFII37KYBkzkZ+ZkvouhmxMVCO+n8qo1oTmQ==", + "requires": { + "json-rpc-engine": "^3.7.3", + "json-rpc-middleware-stream": "^1.0.1", + "loglevel": "^1.6.1", + "obj-multiplex": "^1.0.0", + "obs-store": "^3.0.0", + "pump": "^3.0.0" + }, + "dependencies": { + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=" + } + } + }, "metamask-logo": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/metamask-logo/-/metamask-logo-2.1.4.tgz", @@ -29583,6 +29651,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, "requires": { "is-typedarray": "^1.0.0" } @@ -30572,6 +30641,7 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.3.tgz", "integrity": "sha1-yqRDc9yIFayHZ73ba6cwc5ZMqos=", "requires": { + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -30580,7 +30650,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" } } }, @@ -30978,7 +31048,8 @@ "dev": true, "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.34", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { "underscore": { @@ -30989,7 +31060,8 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "dev": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -31578,7 +31650,8 @@ "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "dev": true }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index 1e0215a8d..950374465 100644 --- a/package.json +++ b/package.json @@ -107,12 +107,12 @@ "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^4.0.1", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", - "eth-json-rpc-middleware": "^2.4.0", - "eth-keyring-controller": "^3.1.4", "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^1.2.2", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", + "eth-json-rpc-middleware": "^2.4.0", + "eth-keyring-controller": "^3.1.4", "eth-ledger-bridge-keyring": "^0.1.0", "eth-method-registry": "^1.0.0", "eth-phishing-detect": "^1.1.4", @@ -131,6 +131,7 @@ "ethjs-query": "^0.3.4", "express": "^4.15.5", "extension-link-enabler": "^1.0.0", + "extension-port-stream": "^1.0.0", "extensionizer": "^1.0.1", "fast-json-patch": "^2.0.4", "fast-levenshtein": "^2.0.6", @@ -157,6 +158,7 @@ "lodash.uniqby": "^4.7.0", "loglevel": "^1.4.1", "metamascara": "^2.0.0", + "metamask-inpage-provider": "^1.0.0", "metamask-logo": "^2.1.4", "mkdirp": "^0.5.1", "multihashes": "^0.4.12", -- cgit