From e9043f22dfa7856e3360b312ce480e71f36d9381 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 21 Sep 2017 15:47:25 -0700 Subject: [PATCH 1/4] Allow custom encryptor to be passed to MetaMaskController and KeyringControllers. --- app/scripts/keyring-controller.js | 2 +- app/scripts/metamask-controller.js | 3 ++- test/unit/keyring-controller-test.js | 5 +---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index fd57fac70..adfa4a813 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -36,7 +36,7 @@ class KeyringController extends EventEmitter { identities: {}, }) this.ethStore = opts.ethStore - this.encryptor = encryptor + this.encryptor = opts.encryptor || encryptor this.keyrings = [] this.getNetwork = opts.getNetwork } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index fef16c3a9..42248827f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -95,6 +95,7 @@ module.exports = class MetamaskController extends EventEmitter { initState: initState.KeyringController, ethStore: this.ethStore, getNetwork: this.networkController.getNetworkState.bind(this.networkController), + encryptor: opts.encryptor || undefined, }) this.keyringController.on('newAccount', (address) => { this.preferencesController.setSelectedAddress(address) @@ -674,4 +675,4 @@ module.exports = class MetamaskController extends EventEmitter { return Promise.resolve(rpcTarget) }) } -} \ No newline at end of file +} diff --git a/test/unit/keyring-controller-test.js b/test/unit/keyring-controller-test.js index 2d9a53723..8d0d75f12 100644 --- a/test/unit/keyring-controller-test.js +++ b/test/unit/keyring-controller-test.js @@ -27,12 +27,9 @@ describe('KeyringController', function () { ethStore: { addAccount (acct) { accounts.push(ethUtil.addHexPrefix(acct)) }, }, + encryptor: mockEncryptor, }) - // Stub out the browser crypto for a mock encryptor. - // Browser crypto is tested in the integration test suite. - keyringController.encryptor = mockEncryptor - keyringController.createNewVaultAndKeychain(password) .then(function (newState) { newState From b25d4d5cfbf9a49e2669188198abd7377e697206 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 21 Sep 2017 15:56:44 -0700 Subject: [PATCH 2/4] Add platform docs including encryptor param --- docs/porting_to_new_environment.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md index 85670efa7..c6336b9f9 100644 --- a/docs/porting_to_new_environment.md +++ b/docs/porting_to_new_environment.md @@ -6,10 +6,31 @@ MetaMask has been under continuous development for nearly two years now, and we The core functionality of MetaMask all lives in what we call [The MetaMask Controller](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js). Our goal for this file is for it to eventually be its own javascript module that can be imported into any JS-compatible context, allowing it to fully manage an app's relationship to Ethereum. -The MM Controller exposes most of its functionality via two methods: +#### Constructor -- [metamask.getState()](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js#L241) - This method returns a javascript object representing the current MetaMask state. This includes things like known accounts, sent transactions, current exchange rates, and more! The controller is also an event emitter, so you can subscribe to state updates via `metamask.on('update', handleStateUpdate)`. State examples available [here](https://github.com/MetaMask/metamask-extension/tree/master/development/states) under the `metamask` key. (Warning: some are outdated) -- [metamask.getApi()](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js#L274-L335) - Returns a JavaScript object filled with callback functions representing every operation our user interface ever performs. Everything from creating new accounts, changing the current network, to sending a transaction, is provided via these API methods. We export this external API on an object because it allows us to easily expose this API over a port using [dnode](https://www.npmjs.com/package/dnode), which is how our WebExtension's UI works! +When calling `new MetaMask(opts)`, many platform-specific options are configured. The keys on `opts` are as follows: + +- initState: The last emitted state, used for restoring persistent state between sessions. +- platform: The `platform` object defines a variety of platform-specific functions, including opening the confirmation view, and customizing the encryption method. + +##### Platform Options + +The `platform` object has a variety of options: + +- reload (function) - Will be called when MetaMask would like to reload its own context. +- openWindow ({ url }) - Will be called when MetaMask would like to open a web page. It will be passed a single `options` object with a `url` key, with a string value. +- getVersion() - Should return the current MetaMask version, as described in the current `CHANGELOG.md` or `app/manifest.json`. +- encryptor - An object that includes two methods: + - encrypt(password, object) - returns a Promise of a string that is ready for storage. + - decrypt(password, encryptedString) - Accepts the encrypted output of `encrypt` and returns a Promise of a restored `object` as it was encrypted. + +#### [metamask.getState()](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js#L241) + +This method returns a javascript object representing the current MetaMask state. This includes things like known accounts, sent transactions, current exchange rates, and more! The controller is also an event emitter, so you can subscribe to state updates via `metamask.on('update', handleStateUpdate)`. State examples available [here](https://github.com/MetaMask/metamask-extension/tree/master/development/states) under the `metamask` key. (Warning: some are outdated) + +#### [metamask.getApi()](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js#L274-L335) + +Returns a JavaScript object filled with callback functions representing every operation our user interface ever performs. Everything from creating new accounts, changing the current network, to sending a transaction, is provided via these API methods. We export this external API on an object because it allows us to easily expose this API over a port using [dnode](https://www.npmjs.com/package/dnode), which is how our WebExtension's UI works! ### The UI @@ -62,4 +83,4 @@ If streams seem new and confusing to you, that's ok, they can seem strange at fi ## Conclusion -I hope this has been helpful to you! If you have any other questionsm, or points you think need clarification in this guide, please [open an issue on our GitHub](https://github.com/MetaMask/metamask-plugin/issues/new)! \ No newline at end of file +I hope this has been helpful to you! If you have any other questionsm, or points you think need clarification in this guide, please [open an issue on our GitHub](https://github.com/MetaMask/metamask-plugin/issues/new)! From e9b7fd901862f57a92614b19f7f2caa969d4a282 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 22 Sep 2017 10:41:14 -0700 Subject: [PATCH 3/4] Patch security update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d02f1df5..bcfb6c1ac 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "redux": "^3.0.5", "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", - "request-promise": "^4.1.1", + "request-promise": "^4.2.1", "sandwich-expando": "^1.0.5", "semaphore": "^1.0.5", "sw-stream": "^2.0.0", From 4c971ebfd1fad18368ec418c36c4d05a6bb37e6d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 22 Sep 2017 13:25:08 -0700 Subject: [PATCH 4/4] Define encryptor in constructor params instead of platform object --- app/scripts/metamask-controller.js | 2 +- docs/porting_to_new_environment.md | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e4fa3518f..42248827f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -95,7 +95,7 @@ module.exports = class MetamaskController extends EventEmitter { initState: initState.KeyringController, ethStore: this.ethStore, getNetwork: this.networkController.getNetworkState.bind(this.networkController), - encryptor: opts.platform.encryptor || undefined, + encryptor: opts.encryptor || undefined, }) this.keyringController.on('newAccount', (address) => { this.preferencesController.setSelectedAddress(address) diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md index c6336b9f9..729a28e5d 100644 --- a/docs/porting_to_new_environment.md +++ b/docs/porting_to_new_environment.md @@ -11,7 +11,16 @@ The core functionality of MetaMask all lives in what we call [The MetaMask Contr When calling `new MetaMask(opts)`, many platform-specific options are configured. The keys on `opts` are as follows: - initState: The last emitted state, used for restoring persistent state between sessions. -- platform: The `platform` object defines a variety of platform-specific functions, including opening the confirmation view, and customizing the encryption method. +- platform: The `platform` object defines a variety of platform-specific functions, including opening the confirmation view, and opening web sites. +- encryptor - An object that provides access to the desired encryption methods. + +##### Encryptor + +An object that provides two simple methods, which can encrypt in any format you prefer. This parameter is optional, and will default to the browser-native WebCrypto API. + +- encrypt(password, object) - returns a Promise of a string that is ready for storage. +- decrypt(password, encryptedString) - Accepts the encrypted output of `encrypt` and returns a Promise of a restored `object` as it was encrypted. + ##### Platform Options @@ -20,9 +29,6 @@ The `platform` object has a variety of options: - reload (function) - Will be called when MetaMask would like to reload its own context. - openWindow ({ url }) - Will be called when MetaMask would like to open a web page. It will be passed a single `options` object with a `url` key, with a string value. - getVersion() - Should return the current MetaMask version, as described in the current `CHANGELOG.md` or `app/manifest.json`. -- encryptor - An object that includes two methods: - - encrypt(password, object) - returns a Promise of a string that is ready for storage. - - decrypt(password, encryptedString) - Accepts the encrypted output of `encrypt` and returns a Promise of a restored `object` as it was encrypted. #### [metamask.getState()](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/metamask-controller.js#L241)