aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/metamask-controller.js45
-rw-r--r--docs/porting_to_new_environment.md35
2 files changed, 65 insertions, 15 deletions
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 393154c60..17d38d43c 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -1391,6 +1391,32 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {string} origin - The URI of the requesting resource.
*/
setupProviderConnection (outStream, origin, publicApi) {
+ const getSiteMetadata = publicApi && publicApi.getSiteMetadata
+ const engine = this.setupProviderEngine(origin, getSiteMetadata)
+
+ // setup connection
+ const providerStream = createEngineStream({ engine })
+
+ pump(
+ outStream,
+ providerStream,
+ outStream,
+ (err) => {
+ // cleanup filter polyfill middleware
+ engine._middleware.forEach((mid) => {
+ if (mid.destroy && typeof mid.destroy === 'function') {
+ mid.destroy()
+ }
+ })
+ if (err) log.error(err)
+ }
+ )
+ }
+
+ /**
+ * A method for creating a provider that is safely restricted for the requesting domain.
+ **/
+ setupProviderEngine (origin, getSiteMetadata) {
// setup json rpc engine stack
const engine = new RpcEngine()
const provider = this.provider
@@ -1398,6 +1424,7 @@ module.exports = class MetamaskController extends EventEmitter {
// create filter polyfill middleware
const filterMiddleware = createFilterMiddleware({ provider, blockTracker })
+
// create subscription polyfill middleware
const subscriptionManager = createSubscriptionManager({ provider, blockTracker })
subscriptionManager.events.on('notification', (message) => engine.emit('notification', message))
@@ -1413,24 +1440,11 @@ module.exports = class MetamaskController extends EventEmitter {
// requestAccounts
engine.push(this.providerApprovalController.createMiddleware({
origin,
- getSiteMetadata: publicApi && publicApi.getSiteMetadata,
+ getSiteMetadata,
}))
// forward to metamask primary provider
engine.push(providerAsMiddleware(provider))
-
- // setup connection
- const providerStream = createEngineStream({ engine })
-
- pump(
- outStream,
- providerStream,
- outStream,
- (err) => {
- // cleanup filter polyfill middleware
- filterMiddleware.destroy()
- if (err) log.error(err)
- }
- )
+ return engine
}
/**
@@ -1797,3 +1811,4 @@ module.exports = class MetamaskController extends EventEmitter {
return this.keyringController.setLocked()
}
}
+
diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md
index 9c4021781..070ab69fa 100644
--- a/docs/porting_to_new_environment.md
+++ b/docs/porting_to_new_environment.md
@@ -10,6 +10,41 @@ The `metamask-background` describes the file at `app/scripts/background.js`, whi
When a new site is visited, the WebExtension creates a new `ContentScript` in that page's context, which can be seen at `app/scripts/contentscript.js`. This script represents a per-page setup process, which creates the per-page `web3` api, connects it to the background script via the Port API (wrapped in a [stream abstraction](https://github.com/substack/stream-handbook)), and injected into the DOM before anything loads.
+You can choose to use this streaming interface to connect to the MetaMask controller over any transport you can wrap with a stream, by connecting it to the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider), but you can also construct a provider per domain like this:
+
+```javascript
+const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine')
+
+/**
+* returns a provider restricted to the requesting domain
+**/
+function incomingConnection (domain, getSiteMetadata) {
+ const engine = metamaskController.setupProviderEngine(domain, getSiteMetadata)
+ const provider = providerFromEngine(engine)
+ return provider
+}
+```
+
+Please note if you take this approach, you are responsible for cleaning up the filters when the page is closed:
+
+```
+const filterMiddleware = engine._middleware.filter(mid => mid.name === 'filterMiddleware')[0]
+filterMiddleware.destroy()
+```
+
+### getSiteMetadata()
+
+This method is used to enhance our confirmation screens with images and text representing the requesting domain.
+
+It should return a promise that resolves with an object with the following properties:
+
+- `name`: The requesting site's name.
+- `icon`: A URI representing the site's logo.
+
+### Using the Streams Interface
+
+Only use this if you intend to construct the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider) over a stream!
+
The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API over a series of streams between contexts. Once you understand how we create the [MetamaskInpageProvider](https://github.com/MetaMask/metamask-inpage-provider/blob/master/index.js) in the [inpage.js script](../app/scripts/inpage.js), you will be able to understand how the [port-stream](../app/scripts/lib/port-stream.js) is just a thin wrapper around the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage), and a similar stream API can be wrapped around any communication channel to communicate with the `MetaMaskController` via its `setupUntrustedCommunication(stream, domain)` method.
### The MetaMask Controller