Automatically merged updates to draft EIP(s) 1102

Hi, I'm a bot! This change was automatically merged because:

 - It only modifies existing Draft or Last Call EIP(s)
 - The PR was approved or written by at least one author of each modified EIP
 - The build is passing
This commit is contained in:
Paul Bouchon 2018-09-02 20:02:56 -04:00 committed by EIP Automerge Bot
parent 7dbcbc35e4
commit 2df99653a0

View File

@ -11,17 +11,39 @@ created: 2018-05-04
## Simple summary
This proposal describes a way for DOM environments to expose an Ethereum provider API that requires user approval.
This proposal describes a way for DOM environments to expose an Ethereum provider that requires user approval.
## Abstract
The previous generation of Ethereum-enabled DOM environments follows a pattern of directly injecting a provider object into the DOM without user consent. This exposes users of such environments to fingerprinting attacks since untrusted websites can check for the injected provider and reliably identify Ethereum-enabled clients.
The previous generation of Ethereum-enabled DOM environments follows a pattern of injecting a fully-enabled provider into the DOM without user consent. This puts users of such environments at risk because malicious websites can use this provider to view account information and to arbitrarily initiate unwanted Ethereum transactions on a user's behalf.
This proposal outlines a protocol in which dapps request access to an Ethereum provider API.
This proposal outlines a protocol in which DOM environments expose a read-only provider until full provider access is approved by the user.
## Specification
### Typical dapp initialization
### Definitions
1. **Read-only provider**
A read-only provider has no populated accounts and any RPC request that requires an account will fail.
2. **Full provider**
A full provider has populated accounts and any RPC request that requires an account will succeed.
3. **`Provider#enable`**
Providers exposed by DOM environments define a new `enable` method that returns a Promise. Calling this method triggers a user interface that allows the user to approve or deny full provider access for a given dapp. The returned Promise is resolved if the user approves full provider access or rejected if the user denies full provider access.
```js
ethereum.enable(): Promise<any>
```
### Protocol
DOM environments expose a read-only provider globally at `window.ethereum` by default. Before initiating any RPC request that requires an account, like `eth_sendTransaction`, dapps must request a full provider by calling a new provider method, `ethereum.enable()`. This method triggers a user interface that allows the user to approve or deny full provider access for a given dapp. If the user approves full provider access, the provider at `window.ethereum` is populated with accounts and fully-enabled; if the user denies full provider access, the provider at `window.ethereum` is left unchanged.
#### Typical dapp initialization
```
START dapp
@ -31,62 +53,71 @@ IF web3 is undefined
STOP dapp
```
### Proposed dapp initialization
#### Proposed dapp initialization
```
START dapp
REQUEST[1] provider
IF user approves
RESPOND[2] with provider
CONTINUE dapp
IF user rejects
IF non-Ethereum environment
NOOP[3]
IF provider is defined
ENABLE[1] full provider
IF user approves
RESOLVE[2] full provider
CONTINUE dapp
IF user denies
REJECT[3] with error
STOP dapp
IF provider is undefined
STOP dapp
```
#### `[1] REQUEST`
##### `[1] ENABLE`
Dapps MUST request an Ethereum provider API by sending a message using the [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) API. This message MUST be sent with a payload object containing a `type` property with a value of "ETHEREUM_PROVIDER_REQUEST" and an optional `id` property corresponding to an identifier of a specific wallet provider, such as "METAMASK".
Dapps MUST request a full provider by calling the `enable` method on the default read-only provider. This method MUST trigger a user interface that allows the user to approve or deny full provider access for a given dapp. This method MUST return a Promise that is resolved if the user approves full provider access or rejected if the user denies full provider access.
#### `[2] RESPOND`
##### `[2] RESOLVE`
Ethereum-enabled DOM environments MUST respond with an Ethereum provider API by emitting an "ethereumprovider" [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent) on the `window` object. This custom event MUST pass a provider API as an `ethereum` property on its `detail` data object.
If a user approves full provider access, DOM environments MUST expose a fully-enabled provider at `window.ethereum` that is populated with accounts. The Promise returned when calling the `enable` method MUST be resolved.
#### `[3] NOOP`
##### `[3] REJECT`
If a user rejects access to the Ethereum provider API on an untrusted site, the site itself MUST NOT be notified in any way; notification of a rejection would allow third-party tools to still identify that a client is Ethereum-enabled despite not being granted access to any provider API.
If a user denies full provider access, the Promise returned when calling the `enable` method MUST be rejected with an informative Error.
### Example implementation: `postMessage`
The following example demonstrates one possible implementation of this strategy in a browser-based DOM environment. Note that Ethereum-enabled environments on other platforms would most likely use platform-specific native messaging protocols, not `postMessage`.
### Example initialization
```js
window.addEventListener('load', () => {
// Listen for provider response
window.addEventListener('ethereumprovider', async ({ detail: { ethereum } }) => {
// Provider API exposed, continue
const networkVersion = await ethereum.send('net_version', []);
});
// Request provider
window.postMessage({ type: 'ETHEREUM_PROVIDER_REQUEST' }, '*');
window.addEventListener('load', async () => {
// Read-only provider is exposed by default
console.log(await ethereum.send('net_version'));
try {
// Request full provider if needed
await ethereum.enable();
// Full provider exposed
await ethereum.send('eth_sendTransaction', [/* ... */]);
} catch (error) {
// User denied full provider access
}
});
```
## Rationale
The pattern of provider auto-injection followed by the previous generation of Ethereum-enabled DOM environments failed to protect user privacy by allowing untrusted websites to uniquely identify Ethereum users. This proposal establishes a new pattern wherein dapps must request access to an Ethereum provider API. This protocol directly prevents fingerprinting attacks by giving users the ability to reject provider exposure on a given website.
### Constraints
* A provider API MUST NOT be exposed to websites by default.
* Dapps MUST request a provider API if it does not exist.
* Users MUST be able to approve or reject provider API access.
* A provider API MUST be exposed to websites after user consent.
* Environments MAY continue auto-exposing a provider API if users can opt-out.
* Browsers MUST expose a read-only provider at `window.ethereum` by default.
* Browsers MUST NOT expose a full provider globally by default.
* Dapps MUST request access to a full provider.
* Users MUST be able to approve or deny full provider access.
* A full provider MUST be exposed at `window.ethereum` after user approval.
* Dapps MUST be notified of user approval of full provider access.
* Dapps MUST be notified of user denial of full provider access.
## Rationale
The pattern of full provider auto-injection followed by the previous generation of Ethereum-enabled DOM environments fails to protect user privacy and fails to maintain safe user experience: untrusted websites can both view account information and arbitrarily initiate transactions on a user's behalf. Even though most users may reject unsolicited transactions on untrusted websites, a protocol for provider exposure should make such unsolicited requests impossible.
This proposal establishes a new pattern wherein dapps must request access to a full Ethereum provider. This protocol directly strengthens user privacy by hiding user accounts and preventing unsolicited transaction requests on untrusted sites.
### Immediate value-add
* Users can reject provider API access on untrusted sites to prevent fingerprinting.
* Users can reject full provider access on untrusted sites to hide accounts.
* Users can reject full provider access on untrusted sites to prevent unsolicited transactions.
### Long-term value-add
@ -97,7 +128,7 @@ The pattern of provider auto-injection followed by the previous generation of Et
## Backwards compatibility
This proposal impacts dapp authors and requires that they request access to an Ethereum provider API before using it. This proposal also impacts developers of Ethereum-enabled environments or dapp browsers as these tools should no longer auto-expose any provider API; instead, they should only do so if a website requests a provider API and if the user consents to its access. Environments may continue to auto-expose an Ethereum provider API as long as users have the ability to disable this behavior.
This proposal impacts dapp authors and requires that they request access to a full Ethereum provider before using it to initiate any RPC call that requires an account. This proposal also impacts developers of Ethereum-enabled DOM environments or dapp browsers as these tools should no longer auto-expose a full provider populated with accounts; instead, they should expose a read-only provider and only expose a full provider if a website requests one and a user consents to its access.
## Implementation