From 6731a640a28e148592aec7208791f23b7a9b4dfd Mon Sep 17 00:00:00 2001 From: prathamesh0 <42446521+prathamesh0@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:34:02 +0530 Subject: [PATCH] Use a single payment header in payments plugin (#393) * Add client address field to payments manager * Use a single payment header in payments plugin * Upgrade ts-nitro packages * Rename method to authenticateVoucherForSender * Upgrade package versions --------- Co-authored-by: Nabarun --- lerna.json | 2 +- packages/cache/package.json | 2 +- packages/cli/package.json | 6 +- packages/codegen/package.json | 4 +- .../src/templates/package-template.handlebars | 10 ++-- packages/graph-node/package.json | 10 ++-- packages/ipld-eth-client/package.json | 4 +- packages/peer/package.json | 2 +- packages/solidity-mapper/package.json | 4 +- packages/test/package.json | 2 +- packages/tracing-client/package.json | 2 +- packages/util/package.json | 11 ++-- packages/util/src/payments.ts | 57 +++++++++++-------- yarn.lock | 18 +++--- 14 files changed, 71 insertions(+), 63 deletions(-) diff --git a/lerna.json b/lerna.json index eafef4d4..07f2162a 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.2.48", + "version": "0.2.49", "npmClient": "yarn", "useWorkspaces": true, "command": { diff --git a/packages/cache/package.json b/packages/cache/package.json index e0c2c415..940d0e4c 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/cache", - "version": "0.2.48", + "version": "0.2.49", "description": "Generic object cache", "main": "dist/index.js", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 8e06ced1..99dd6205 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/cli", - "version": "0.2.48", + "version": "0.2.49", "main": "dist/index.js", "license": "AGPL-3.0", "scripts": { @@ -11,8 +11,8 @@ "chat": "DEBUG='vulcanize:*, laconic:*' node dist/chat.js" }, "dependencies": { - "@cerc-io/peer": "^0.2.48", - "@cerc-io/util": "^0.2.48", + "@cerc-io/peer": "^0.2.49", + "@cerc-io/util": "^0.2.49", "@ethersproject/providers": "^5.4.4", "@graphql-tools/utils": "^9.1.1", "@ipld/dag-cbor": "^8.0.0", diff --git a/packages/codegen/package.json b/packages/codegen/package.json index f7519d3f..113d0fbb 100644 --- a/packages/codegen/package.json +++ b/packages/codegen/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/codegen", - "version": "0.2.48", + "version": "0.2.49", "description": "Code generator", "private": true, "main": "index.js", @@ -20,7 +20,7 @@ }, "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { - "@cerc-io/util": "^0.2.48", + "@cerc-io/util": "^0.2.49", "@graphql-tools/load-files": "^6.5.2", "@poanet/solidity-flattener": "https://github.com/vulcanize/solidity-flattener.git", "@solidity-parser/parser": "^0.13.2", diff --git a/packages/codegen/src/templates/package-template.handlebars b/packages/codegen/src/templates/package-template.handlebars index 2ce8b3dc..352c292b 100644 --- a/packages/codegen/src/templates/package-template.handlebars +++ b/packages/codegen/src/templates/package-template.handlebars @@ -41,12 +41,12 @@ "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { "@apollo/client": "^3.3.19", - "@cerc-io/cli": "^0.2.48", - "@cerc-io/ipld-eth-client": "^0.2.48", - "@cerc-io/solidity-mapper": "^0.2.48", - "@cerc-io/util": "^0.2.48", + "@cerc-io/cli": "^0.2.49", + "@cerc-io/ipld-eth-client": "^0.2.49", + "@cerc-io/solidity-mapper": "^0.2.49", + "@cerc-io/util": "^0.2.49", {{#if (subgraphPath)}} - "@cerc-io/graph-node": "^0.2.48", + "@cerc-io/graph-node": "^0.2.49", {{/if}} "@ethersproject/providers": "^5.4.4", "apollo-type-bigint": "^0.1.3", diff --git a/packages/graph-node/package.json b/packages/graph-node/package.json index a6334a85..18e4eaa6 100644 --- a/packages/graph-node/package.json +++ b/packages/graph-node/package.json @@ -1,10 +1,10 @@ { "name": "@cerc-io/graph-node", - "version": "0.2.48", + "version": "0.2.49", "main": "dist/index.js", "license": "AGPL-3.0", "devDependencies": { - "@cerc-io/solidity-mapper": "^0.2.48", + "@cerc-io/solidity-mapper": "^0.2.49", "@ethersproject/providers": "^5.4.4", "@graphprotocol/graph-ts": "^0.22.0", "@nomiclabs/hardhat-ethers": "^2.0.2", @@ -51,9 +51,9 @@ "dependencies": { "@apollo/client": "^3.3.19", "@cerc-io/assemblyscript": "0.19.10-watcher-ts-0.1.2", - "@cerc-io/cache": "^0.2.48", - "@cerc-io/ipld-eth-client": "^0.2.48", - "@cerc-io/util": "^0.2.48", + "@cerc-io/cache": "^0.2.49", + "@cerc-io/ipld-eth-client": "^0.2.49", + "@cerc-io/util": "^0.2.49", "@types/json-diff": "^0.5.2", "@types/yargs": "^17.0.0", "bn.js": "^4.11.9", diff --git a/packages/ipld-eth-client/package.json b/packages/ipld-eth-client/package.json index a20472d4..04141be9 100644 --- a/packages/ipld-eth-client/package.json +++ b/packages/ipld-eth-client/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/ipld-eth-client", - "version": "0.2.48", + "version": "0.2.49", "description": "IPLD ETH Client", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { "@apollo/client": "^3.7.1", - "@cerc-io/cache": "^0.2.48", + "@cerc-io/cache": "^0.2.49", "cross-fetch": "^3.1.4", "debug": "^4.3.1", "ethers": "^5.4.4", diff --git a/packages/peer/package.json b/packages/peer/package.json index a9afea68..5e4bc48e 100644 --- a/packages/peer/package.json +++ b/packages/peer/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/peer", - "version": "0.2.48", + "version": "0.2.49", "description": "libp2p module", "main": "dist/index.js", "exports": "./dist/index.js", diff --git a/packages/solidity-mapper/package.json b/packages/solidity-mapper/package.json index 0bdd1d33..3b67fb06 100644 --- a/packages/solidity-mapper/package.json +++ b/packages/solidity-mapper/package.json @@ -1,10 +1,10 @@ { "name": "@cerc-io/solidity-mapper", - "version": "0.2.48", + "version": "0.2.49", "main": "dist/index.js", "license": "AGPL-3.0", "devDependencies": { - "@cerc-io/ipld-eth-client": "^0.2.48", + "@cerc-io/ipld-eth-client": "^0.2.49", "@ethersproject/abi": "^5.3.0", "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-waffle": "^2.0.1", diff --git a/packages/test/package.json b/packages/test/package.json index 8fe98886..74d8116d 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/test", - "version": "0.2.48", + "version": "0.2.49", "main": "dist/index.js", "license": "AGPL-3.0", "private": true, diff --git a/packages/tracing-client/package.json b/packages/tracing-client/package.json index 0c4de174..794879d8 100644 --- a/packages/tracing-client/package.json +++ b/packages/tracing-client/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/tracing-client", - "version": "0.2.48", + "version": "0.2.49", "description": "ETH VM tracing client", "main": "dist/index.js", "scripts": { diff --git a/packages/util/package.json b/packages/util/package.json index cf0ec19e..c215f321 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,13 +1,12 @@ { "name": "@cerc-io/util", - "version": "0.2.48", + "version": "0.2.49", "main": "dist/index.js", "license": "AGPL-3.0", "dependencies": { "@apollo/utils.keyvaluecache": "^1.0.1", - "@cerc-io/nitro-client": "^0.1.3", - "@cerc-io/nitro-util": "^0.1.3", - "@cerc-io/solidity-mapper": "^0.2.48", + "@cerc-io/nitro-client": "^0.1.4", + "@cerc-io/solidity-mapper": "^0.2.49", "@cerc-io/ts-channel": "1.0.3-ts-nitro-0.1.1", "@ethersproject/providers": "^5.4.4", "@graphql-tools/schema": "^9.0.10", @@ -41,8 +40,8 @@ "yargs": "^17.0.1" }, "devDependencies": { - "@cerc-io/cache": "^0.2.48", - "@cerc-io/ipld-eth-client": "^0.2.48", + "@cerc-io/cache": "^0.2.49", + "@cerc-io/ipld-eth-client": "^0.2.49", "@nomiclabs/hardhat-waffle": "^2.0.1", "@types/express": "^4.17.14", "@types/fs-extra": "^9.0.11", diff --git a/packages/util/src/payments.ts b/packages/util/src/payments.ts index 6118edb2..806c87b7 100644 --- a/packages/util/src/payments.ts +++ b/packages/util/src/payments.ts @@ -1,5 +1,4 @@ import debug from 'debug'; -import { ethers } from 'ethers'; import { LRUCache } from 'lru-cache'; import { FieldNode } from 'graphql'; import { ApolloServerPlugin, GraphQLResponse, GraphQLRequestContext } from 'apollo-server-plugin-base'; @@ -7,22 +6,22 @@ import { Response as HTTPResponse } from 'apollo-server-env'; import Channel from '@cerc-io/ts-channel'; import type { ReadWriteChannel } from '@cerc-io/ts-channel'; -import type { Client, Signature, Voucher } from '@cerc-io/nitro-client'; -import { recoverEthereumMessageSigner, getSignatureFromEthersSignature } from '@cerc-io/nitro-client'; -import { hex2Bytes } from '@cerc-io/nitro-util'; +import type { Client, Voucher } from '@cerc-io/nitro-client'; +import { utils as nitroUtils } from '@cerc-io/nitro-client'; const log = debug('laconic:payments'); const IntrospectionQuery = 'IntrospectionQuery'; -const HASH_HEADER_KEY = 'hash'; -const SIG_HEADER_KEY = 'sig'; +const PAYMENT_HEADER_KEY = 'x-payment'; +const PAYMENT_HEADER_REGEX = /vhash:(.*),vsig:(.*)/; const ERR_FREE_QUOTA_EXHUASTED = 'Free quota exhausted'; const ERR_PAYMENT_NOT_RECEIVED = 'Payment not received'; const HTTP_CODE_PAYMENT_NOT_RECEIVED = 402; // Payment required -const ERR_HEADER_MISSING = 'Header for hash or sig not set'; -const HTTP_CODE_HEADER_MISSING = 400; // Bad request +const ERR_HEADER_MISSING = 'Payment header x-payment not set'; +const ERR_INVALID_PAYMENT_HEADER = 'Invalid payment header format'; +const HTTP_CODE_BAD_REQUEST = 400; // Bad request const EMPTY_VOUCHER_HASH = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'; // keccak256('0x') @@ -38,6 +37,8 @@ const FREE_QUERIES = ['latestBlock']; const REQUEST_TIMEOUT = 10 * 1000; // 10 seconds export class PaymentsManager { + clientAddress?: string; + // TODO: Persist data private remainingFreeQueriesMap: Map = new Map(); @@ -57,6 +58,8 @@ export class PaymentsManager { } async subscribeToVouchers (client: Client): Promise { + this.clientAddress = client.address; + const receivedVouchersChannel = client.receivedVouchers(); log('Starting voucher subscription...'); @@ -107,7 +110,7 @@ export class PaymentsManager { } async allowRequest (voucherHash: string, voucherSig: string): Promise<[boolean, string]> { - const senderAddress = getSenderAddress(voucherHash, voucherSig); + const senderAddress = nitroUtils.getSignerAddress(voucherHash, voucherSig); if (voucherHash === EMPTY_VOUCHER_HASH) { let remainingFreeQueries = this.remainingFreeQueriesMap.get(senderAddress); @@ -128,7 +131,7 @@ export class PaymentsManager { } // Check for payment voucher received from the Nitro account - const paymentVoucherRecived = await this.authenticateVoucherForSender(voucherHash, senderAddress); + const paymentVoucherRecived = await this.authenticateVoucher(voucherHash, senderAddress); if (paymentVoucherRecived) { log(`Serving a paid query for ${senderAddress}`); @@ -139,7 +142,7 @@ export class PaymentsManager { } } - private async authenticateVoucherForSender (voucherHash:string, senderAddress: string): Promise { + async authenticateVoucher (voucherHash:string, senderAddress: string): Promise { if (this.acceptReceivedVouchers(voucherHash, senderAddress)) { return true; } @@ -213,15 +216,28 @@ export const paymentsPlugin = (paymentsManager?: PaymentsManager): ApolloServerP return null; } - const hash = requestContext.request.http?.headers.get(HASH_HEADER_KEY); - const sig = requestContext.request.http?.headers.get(SIG_HEADER_KEY); - - if (hash == null || sig == null) { + const paymentHeader = requestContext.request.http?.headers.get(PAYMENT_HEADER_KEY); + if (paymentHeader == null) { return { errors: [{ message: ERR_HEADER_MISSING }], http: new HTTPResponse(undefined, { headers: requestContext.response?.http?.headers, - status: HTTP_CODE_HEADER_MISSING + status: HTTP_CODE_BAD_REQUEST + }) + }; + } + + let vhash: string, vsig: string; + const match = paymentHeader.match(PAYMENT_HEADER_REGEX); + + if (match) { + [, vhash, vsig] = match; + } else { + return { + errors: [{ message: ERR_INVALID_PAYMENT_HEADER }], + http: new HTTPResponse(undefined, { + headers: requestContext.response?.http?.headers, + status: HTTP_CODE_BAD_REQUEST }) }; } @@ -236,7 +252,7 @@ export const paymentsPlugin = (paymentsManager?: PaymentsManager): ApolloServerP continue; } - const [allowRequest, rejectionMessage] = await paymentsManager.allowRequest(hash, sig); + const [allowRequest, rejectionMessage] = await paymentsManager.allowRequest(vhash, vsig); if (!allowRequest) { const failResponse: GraphQLResponse = { errors: [{ message: rejectionMessage }], @@ -256,10 +272,3 @@ export const paymentsPlugin = (paymentsManager?: PaymentsManager): ApolloServerP } }; }; - -const getSenderAddress = (hash: string, sig: string): string => { - const splitSig = ethers.utils.splitSignature(sig); - const signature: Signature = getSignatureFromEthersSignature(splitSig); - - return recoverEthereumMessageSigner(hex2Bytes(hash), signature); -}; diff --git a/yarn.lock b/yarn.lock index ed2fede7..f21afe03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,13 +350,13 @@ wherearewe "^2.0.0" xsalsa20 "^1.1.0" -"@cerc-io/nitro-client@^0.1.3": - version "0.1.3" - resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fnitro-client/-/0.1.3/nitro-client-0.1.3.tgz#a536da9f6c1bc0f95cd3c4ecc2358be5f36bc8f1" - integrity sha512-fZ8+Diz5tDrBz7t56X5R9ul54FE7tLmyAB//5NY2OBncjthpTmkF0kmQvO2KVyQGuriVTe7FbqwJMtIRWKxWEQ== +"@cerc-io/nitro-client@^0.1.4": + version "0.1.4" + resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fnitro-client/-/0.1.4/nitro-client-0.1.4.tgz#7f69fa5fa66beb7eedd6dddc81a29d2589e6d60d" + integrity sha512-2onCl2wygbXXhtjdMotRdeOXovFeiCegenE/y4uFKxOX83LpslTx/iK+d6HqcQHW4Kkc2pExu6PBntaPoKVpLA== dependencies: "@cerc-io/libp2p" "0.42.2-laconic-0.1.3" - "@cerc-io/nitro-util" "^0.1.3" + "@cerc-io/nitro-util" "^0.1.4" "@cerc-io/peer" "^0.2.46" "@cerc-io/ts-channel" "1.0.3-ts-nitro-0.1.1" "@libp2p/crypto" "^1.0.4" @@ -373,10 +373,10 @@ promjs "^0.4.2" uint8arrays "^4.0.3" -"@cerc-io/nitro-util@^0.1.3": - version "0.1.3" - resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fnitro-util/-/0.1.3/nitro-util-0.1.3.tgz#1c640221c3936203e8ccf492e6374b50502d60d3" - integrity sha512-NTg8RO/3bzGLZie3pavcJJzLeL9gI1RLxwEMVBtRzsZfniDfsu7CTasoEX+hKgyBiZstEoMtGbfpwVmM1IEQBA== +"@cerc-io/nitro-util@^0.1.4": + version "0.1.4" + resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fnitro-util/-/0.1.4/nitro-util-0.1.4.tgz#101f61692050f0ae850b0a0a12e56252f3ddc5a8" + integrity sha512-dqzFA5czCxo/yyAhHMplzRzTyzf52WpU8U+ntZ9zFIfrWPHvHHyDY4YyjA2yVQEWfcyyIZ0GTzf6wDb/kP8dKg== dependencies: assert "^2.0.0" debug "^4.3.4"