From 534c6a9b97b6f7a3aa587d6ca3fde52247976204 Mon Sep 17 00:00:00 2001 From: Anxo Rodriguez Date: Fri, 24 Nov 2023 17:46:14 +0000 Subject: [PATCH] feat: add basic auth --- src/domain/chainContext.ts | 43 +++++++++++++++++++++++++++++++++++--- src/index.ts | 14 +++++++++++-- src/types/index.ts | 2 ++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/domain/chainContext.ts b/src/domain/chainContext.ts index e5c23d0..6af28ab 100644 --- a/src/domain/chainContext.ts +++ b/src/domain/chainContext.ts @@ -31,7 +31,7 @@ import { reorgDepth, reorgsTotal, } from "../utils/metrics"; -import { hexZeroPad } from "ethers/lib/utils"; +import { ConnectionInfo, hexZeroPad } from "ethers/lib/utils"; import { FilterPolicy } from "../utils/filterPolicy"; const WATCHDOG_FREQUENCY = 5 * 1000; // 5 seconds @@ -155,9 +155,9 @@ export class ChainContext { options: RunSingleOptions, storage: DBService ): Promise { - const { rpc, deploymentBlock } = options; + const { rpc, rpcUser, rpcPassword, deploymentBlock } = options; - const provider = new providers.JsonRpcProvider(rpc); + const provider = getProvider(rpc, rpcUser, rpcPassword); const chainId = (await provider.getNetwork()).chainId; const registry = await Registry.load( @@ -444,6 +444,43 @@ export class ChainContext { } } +function getProvider( + rpc: string, + user?: string, + password?: string +): providers.Provider { + const providerConfig: ConnectionInfo = { url: rpc }; + + if (user && password) { + if (rpc.startsWith("http")) { + // FIXME: Not a good idea to use HTTP and basic auth, but this is a temporary solution to support it (some RPCs are only exposes under HTTP and have basic auth) + // Only run it in our own infra + providerConfig.headers = { + Authorization: getAuthHeader({ user, password }), + }; + } else { + // Set basic auth + providerConfig.user = user; + providerConfig.password = password; + } + } + + return new providers.JsonRpcProvider(providerConfig); +} + +/** + * Helper method to create the basic AUTH header for the provider + * In principle, ethersjs already deals with it, however i need to manually set it when using HTTP. + * + * Its not a good idea to use auth headers with HTTP, so this is a temporary solution. + * + * @param params user and password + * @returns the basic auth header + */ +function getAuthHeader({ user, password }: { user: string; password: string }) { + return "Basic " + Buffer.from(`${user}:${password}`).toString("base64"); +} + /** * Process events in a block. * @param context of the chain who's block is being processed diff --git a/src/index.ts b/src/index.ts index 51544be..7151ba3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -71,7 +71,9 @@ const databasePathOption = new Option( .default(DEFAULT_DATABASE_PATH) .env("DATABASE_PATH"); -const chainConfigHelp = `Chain configuration in the format of ,[,,,], e.g. http://erigon.dappnode:8545,12345678,30,https://api.cow.fi/mainnet,https://raw.githubusercontent.com/cowprotocol/watch-tower/config/filter-policy-1.json`; +const CHAIN_CONFIG_PARAMS = + ",[,,,,,"; +const chainConfigHelp = `Chain configuration in the format of ${CHAIN_CONFIG_PARAMS}], e.g. http://erigon.dappnode:8545,12345678,30,https://api.cow.fi/mainnet,https://raw.githubusercontent.com/cowprotocol/watch-tower/config/filter-policy-1.json`; const multiChainConfigOption = new Option( "--chain-config ", chainConfigHelp @@ -231,7 +233,7 @@ function parseChainConfigOption(option: string): ChainConfigOptions { // Ensure there are at least two parts (rpc and deploymentBlock) if (parts.length < 2) { throw new InvalidArgumentError( - `Chain configuration must be in the format of ,[,,,], e.g. http://erigon.dappnode:8545,12345678,30,https://api.cow.fi/mainnet,https://raw.githubusercontent.com/cowprotocol/watch-tower/config/filter-policy-1.json` + `Chain configuration must be in the format of ${CHAIN_CONFIG_PARAMS}], e.g. http://erigon.dappnode:8545,12345678,30,https://api.cow.fi/mainnet,https://raw.githubusercontent.com/cowprotocol/watch-tower/config/filter-policy-1.json` ); } @@ -283,8 +285,16 @@ function parseChainConfigOption(option: string): ChainConfigOptions { ); } + // If there is a sixth part, it is the rpcUser + const rpcUserConfig = parts.length > 5 && parts[5] ? parts[5] : undefined; + + // If there is a seventh part, it is the rpcUser + const rpcPasswordConfig = parts.length > 6 && parts[6] ? parts[6] : undefined; + return { rpc, + rpcUser: rpcUserConfig, + rpcPassword: rpcPasswordConfig, deploymentBlock, watchdogTimeout, orderBookApi, diff --git a/src/types/index.ts b/src/types/index.ts index 56e9689..2a0e344 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -29,6 +29,8 @@ export type ChainConfigOptions = { watchdogTimeout: number; orderBookApi?: string; filterPolicyConfig?: string; + rpcUser?: string; + rpcPassword?: string; // filterPolicyConfigAuthToken?: string; // TODO: Implement authToken };