From 11d6693900ebdbb9595e136fa6c6155e448bc6b8 Mon Sep 17 00:00:00 2001 From: Ronny Esterluss Date: Wed, 15 Nov 2023 09:40:39 +0100 Subject: [PATCH 1/3] initial draft of JSON RPC interception SIP --- SIPS/sip-17.md | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 SIPS/sip-17.md diff --git a/SIPS/sip-17.md b/SIPS/sip-17.md new file mode 100644 index 00000000..42015d5e --- /dev/null +++ b/SIPS/sip-17.md @@ -0,0 +1,121 @@ +--- +sip: (To be assigned) +title: JSON RPC provider +status: Draft +author: Ronny Esterluss (@esterlus) +created: 2023-11-15 +--- + +## Abstract + +Introduce a new endowment that would allow a snap to intercept outgoing traffic and act as a JSON RPC Provider according to [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification). + +## Motivation + +We want to build a snap that gives users full privacy when doing JSON RPC calls using Metamask. +This snap will leverage the power of [RPCh](https://rpch.net/). +The original JSON RPC provider is still the target of the request, but the request will be routed through [HOPRNet](https://network.hoprnet.org/) to eliminate Metadata. + + +## Specification + +> Formal specifications are written in Typescript. + +### Language + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and +"OPTIONAL" written in uppercase in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) + +### Snaps permissions + +This SIP specifies a permission named `endowment:json-rpc-provider`. +The permission signals to the platform that the snap wants to act as a JSON RPC Provider and intercept outgoing JSON RPC requests. + +This permission is specified as follows in `snap.manifest.json` files: + +```json +{ + "initialPermissions": { + "endowment:json-rpc-provider": {} + } +} +``` + +### Snaps exports + +This SIP specifies a new exported event handler `onOutgoingJSONRpcRequest`. +The event handler MUST be called whenever Metamask makes an outgoing JSON RPC request. + +#### Parameters + +An object containing: + +request - The JSON-RPC request +provider - The target JSON RPC Provider + +* request + +This parameter MUST be present and MUST adhere to the official [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification). + +* provider + +This parameter SHOULD be present. It contains the RPC URL of the intented RPC Provider (e.g. `https://mainnet.infura.io/v3/`). +Metamask SHOULD use the configured RPC provider in the currently selected network. + +#### Returns + +A promise resolving to the response of the request or rejecting with an error. + +#### Example + +```typescript +import { OnOutgoingJSONRpcRequestHandler } from '@metamask/snaps-types'; +import RPChSDK from '@rpch/sdk'; + +const sdk = new RPChSDK(""); + +export const onOutgoingJSONRpcRequest: OnOutgoingJSONRpcRequestHandler = async ({ + request, + provider, +}) => { + return sdk.send(request, { provider }); +}; +``` + +#### Type definitions + +```typescript + +type OnOutgoingJSONRpcRequestHandler = + (args: { request: JSONRPCRequest, provider: string }) => Promise; + +type JSONRPCRequest = { + readonly jsonrpc: '2.0'; + id?: string | number | null; + method: string; + params?: any[] | object; +}; + +type JSONRPCResponse = JSONRPCResult | JSONRPCError; + +type JSONRPCResult = { + readonly jsonrpc: '2.0'; + id?: string | number | null; + result: any; +}; + +type JSONRPCError = { + readonly jsonrpc: '2.0'; + id?: string | number | null; + error: { + code: number; + message: string; + data?: any; + }; +}; +``` + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). From cfa0f62a7b1b61eb1fc75fa081580e5b0bc8264a Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Fri, 8 Dec 2023 16:25:05 +0100 Subject: [PATCH 2/3] sip-17: Update proposal to define request middleware --- SIPS/sip-17.md | 138 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 40 deletions(-) diff --git a/SIPS/sip-17.md b/SIPS/sip-17.md index 42015d5e..0120b44e 100644 --- a/SIPS/sip-17.md +++ b/SIPS/sip-17.md @@ -1,21 +1,24 @@ --- sip: (To be assigned) -title: JSON RPC provider +title: Request/Response Middleware status: Draft -author: Ronny Esterluss (@esterlus) +author: Ronny Esterluss (@esterlus), Tino Breddin (@tolbrino) created: 2023-11-15 --- ## Abstract -Introduce a new endowment that would allow a snap to intercept outgoing traffic and act as a JSON RPC Provider according to [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification). +Introduce a new endowment that would allow a snap to register itself as a request middleware. ## Motivation We want to build a snap that gives users full privacy when doing JSON RPC calls using Metamask. -This snap will leverage the power of [RPCh](https://rpch.net/). -The original JSON RPC provider is still the target of the request, but the request will be routed through [HOPRNet](https://network.hoprnet.org/) to eliminate Metadata. - +This snap will leverage [RPCh](https://rpch.net/) to relay requests and +improve the IP-privacy of all RPC calls. +The original JSON RPC provider, which is configured in Metamask for the active +network, will still be used as the target of the request. However the request +will be relayed through [HOPRNet](https://network.hoprnet.org/) first before +finally sent to the RPC provider. ## Specification @@ -25,61 +28,102 @@ The original JSON RPC provider is still the target of the request, but the reque The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and -"OPTIONAL" written in uppercase in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) +"OPTIONAL" written in uppercase in this document are to be interpreted as +described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) ### Snaps permissions -This SIP specifies a permission named `endowment:json-rpc-provider`. -The permission signals to the platform that the snap wants to act as a JSON RPC Provider and intercept outgoing JSON RPC requests. +This SIP specifies a permission named `endowment:request-middleware`. +The permission signals to the platform that the snap wants to act as +request middleware and modify the original requests headers, body and/or target. This permission is specified as follows in `snap.manifest.json` files: ```json { "initialPermissions": { - "endowment:json-rpc-provider": {} + "endowment:request-middleware": {} + } +} +``` + +The order in which the middleware will be called is not guaranteed and may vary. + +3 special types of middlewares are supported: + +1. Middleware entry + Is guaranteed to be called first in the middleware chain. Only a single entry + can be enabled. +2. Middleware exit + Is guaranteed to be called last in the middleware chain. Only a single exit + can be enabled. +3. Execution point + Is guaranteed to be called after the entire middleware chain. Only a single + execution point can be enabled. This middleware will execute the request + directly and return the response. + +The special middleware types can be enabled through permission parameters which +are set to `false` by default: + +```json +{ + "initialPermissions": { + "endowment:request-middleware": { + "isEntry": false, + "isExit": false, + "isExecutionPoint": false + } } } ``` ### Snaps exports -This SIP specifies a new exported event handler `onOutgoingJSONRpcRequest`. -The event handler MUST be called whenever Metamask makes an outgoing JSON RPC request. +This SIP specifies 2 new exported event handlers: `onRequest` and +`onRequestTermination`. +The correct event handler MUST be called whenever Metamask makes an outgoing +JSON RPC request depending on the permission configuration of the middleware. #### Parameters -An object containing: +An object containing the following fields: -request - The JSON-RPC request -provider - The target JSON RPC Provider +* `request`: the request containing headers and body data -* request +`headers`: This parameter MUST be present and be a flat object container key/value mappings. +`body`: This parameter MUST be present and MUST adhere to the official [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification). -This parameter MUST be present and MUST adhere to the official [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification). - -* provider +* `provider`: the target JSON RPC provider url This parameter SHOULD be present. It contains the RPC URL of the intented RPC Provider (e.g. `https://mainnet.infura.io/v3/`). Metamask SHOULD use the configured RPC provider in the currently selected network. #### Returns -A promise resolving to the response of the request or rejecting with an error. +`onRequest`: A promise resolving to the updated request object. +`onRequestTermination`: A promise resolving to the response of the request or rejecting with an error. -#### Example +#### Examples ```typescript -import { OnOutgoingJSONRpcRequestHandler } from '@metamask/snaps-types'; +import { OnRequestHandler, OnRequestTerminationHandler } from '@metamask/snaps-types'; import RPChSDK from '@rpch/sdk'; const sdk = new RPChSDK(""); -export const onOutgoingJSONRpcRequest: OnOutgoingJSONRpcRequestHandler = async ({ +export const onRequest: OnRequestHandler = async ({ + request, + provider, +}) => { + request.headers["CUSTOM-HEADER"] = "example value"; + return request; +}; + +export const onRequest: OnRequestTerminationHandler = async ({ request, provider, }) => { - return sdk.send(request, { provider }); + return sdk.send(request, { provider }); }; ``` @@ -87,32 +131,46 @@ export const onOutgoingJSONRpcRequest: OnOutgoingJSONRpcRequestHandler = async ( ```typescript -type OnOutgoingJSONRpcRequestHandler = - (args: { request: JSONRPCRequest, provider: string }) => Promise; +type OnRequestHandler = + (args: { request: Request, provider: string }) => Promise; + +type OnRequestTerminationHandler = + (args: { request: Request, provider: string }) => Promise; + +type Request = { + headers: object; + body: JSONRPCRequest; +}; type JSONRPCRequest = { - readonly jsonrpc: '2.0'; - id?: string | number | null; - method: string; - params?: any[] | object; + readonly jsonrpc: '2.0'; + id?: string | number | null; + method: string; + params?: any[] | object; +}; + +type Response = { + headers: object; + body: JSONRPCResponse; + status: number; }; type JSONRPCResponse = JSONRPCResult | JSONRPCError; type JSONRPCResult = { - readonly jsonrpc: '2.0'; - id?: string | number | null; - result: any; + readonly jsonrpc: '2.0'; + id?: string | number | null; + result: any; }; type JSONRPCError = { - readonly jsonrpc: '2.0'; - id?: string | number | null; - error: { - code: number; - message: string; - data?: any; - }; + readonly jsonrpc: '2.0'; + id?: string | number | null; + error: { + code: number; + message: string; + data?: any; + }; }; ``` From 732952ea903e0eaf247b1b41a454acdbf63fe984 Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Tue, 2 Jan 2024 19:25:15 +0100 Subject: [PATCH 3/3] Update SIPS/sip-17.md Co-authored-by: Hassan Malik <41640681+hmalik88@users.noreply.github.com> --- SIPS/sip-17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SIPS/sip-17.md b/SIPS/sip-17.md index 0120b44e..2a73aae3 100644 --- a/SIPS/sip-17.md +++ b/SIPS/sip-17.md @@ -1,5 +1,5 @@ --- -sip: (To be assigned) +sip: 17 title: Request/Response Middleware status: Draft author: Ronny Esterluss (@esterlus), Tino Breddin (@tolbrino)