diff --git a/packages/phone-number-privacy/combiner/package.json b/packages/phone-number-privacy/combiner/package.json index 47e7b4d68a6..d252fa288bc 100644 --- a/packages/phone-number-privacy/combiner/package.json +++ b/packages/phone-number-privacy/combiner/package.json @@ -1,6 +1,6 @@ { "name": "@celo/phone-number-privacy-combiner", - "version": "3.0.1", + "version": "3.0.1-beta.0-dev", "description": "Orchestrates and combines threshold signatures for use in ODIS", "author": "Celo", "license": "Apache-2.0", @@ -54,6 +54,7 @@ "express": "^4.17.1", "firebase-admin": "^11.10.1", "firebase-functions": "^4.4.1", + "http-proxy": "^1.18.1", "knex": "^2.1.0", "node-fetch": "^2.6.9", "pg": "^8.2.1", @@ -64,6 +65,7 @@ "@celo/utils": "^5.0.4", "@celo/phone-utils": "^5.0.4", "@types/express": "^4.17.6", + "@types/http-proxy":"^1.17.11", "@types/supertest": "^2.0.12", "@types/uuid": "^7.0.3", "firebase-functions-test": "^3.1.0", diff --git a/packages/phone-number-privacy/combiner/src/config.ts b/packages/phone-number-privacy/combiner/src/config.ts index 2097dbfb5e2..d09ea2cd3d6 100644 --- a/packages/phone-number-privacy/combiner/src/config.ts +++ b/packages/phone-number-privacy/combiner/src/config.ts @@ -41,12 +41,16 @@ export interface OdisConfig { fullNodeRetryDelayMs: number shouldAuthenticate: boolean } - +export interface ProxyConfig { + deploymentEnv: string + forwardToGen2: boolean +} export interface CombinerConfig { serviceName: string blockchain: BlockchainConfig phoneNumberPrivacy: OdisConfig domains: OdisConfig + proxy: ProxyConfig } let config: CombinerConfig @@ -144,6 +148,10 @@ if (DEV_MODE) { fullNodeRetryDelayMs: RETRY_DELAY_IN_MS, shouldAuthenticate: true, }, + proxy: { + forwardToGen2: false, + deploymentEnv: 'local', + }, } } else { const functionConfig = functions.config() @@ -186,13 +194,19 @@ if (DEV_MODE) { currentVersion: Number(functionConfig.domains_keys.current_version), versions: functionConfig.domains_keys.versions, }, - fullNodeTimeoutMs: Number(functionConfig.pnp.full_node_timeout_ms ?? FULL_NODE_TIMEOUT_IN_MS), // TODO refactor config - domains endpoints don't use full node - fullNodeRetryCount: Number(functionConfig.pnp.full_node_retry_count ?? RETRY_COUNT), + fullNodeTimeoutMs: Number( + functionConfig.domains.full_node_timeout_ms ?? FULL_NODE_TIMEOUT_IN_MS + ), // TODO refactor config - domains endpoints don't use full node + fullNodeRetryCount: Number(functionConfig.domains.full_node_retry_count ?? RETRY_COUNT), fullNodeRetryDelayMs: Number( - functionConfig.pnp.full_node_retry_delay_ms ?? RETRY_DELAY_IN_MS + functionConfig.domains.full_node_retry_delay_ms ?? RETRY_DELAY_IN_MS ), shouldAuthenticate: true, }, + proxy: { + forwardToGen2: toBool(functionConfig.proxy.forward_to_gen2, false), + deploymentEnv: functionConfig.proxy.deployment_env, + }, } } export default config diff --git a/packages/phone-number-privacy/combiner/src/index.ts b/packages/phone-number-privacy/combiner/src/index.ts index 02297508a86..1c2e9a31c05 100644 --- a/packages/phone-number-privacy/combiner/src/index.ts +++ b/packages/phone-number-privacy/combiner/src/index.ts @@ -1,6 +1,6 @@ import * as functions from 'firebase-functions' import config from './config' -import { startCombiner } from './server' +import { startCombiner, startProxy } from './server' require('dotenv').config() @@ -12,6 +12,12 @@ export const combiner = functions minInstances: functions.config().service ? Number(functions.config().service.min_instances) : 0, memory: functions.config().service ? functions.config().service.memory : '512MB', }) - .https.onRequest(startCombiner(config)) - + .https.onRequest((req, res) => { + if (config.proxy.forwardToGen2) { + startProxy(req, res, config) + } else { + const app = startCombiner(config) + app(req, res) + } + }) export * from './config' diff --git a/packages/phone-number-privacy/combiner/src/server.ts b/packages/phone-number-privacy/combiner/src/server.ts index 94ca03ffcf1..4d3d318b994 100644 --- a/packages/phone-number-privacy/combiner/src/server.ts +++ b/packages/phone-number-privacy/combiner/src/server.ts @@ -1,6 +1,7 @@ import { ContractKit } from '@celo/contractkit' import { CombinerEndpoint, + ErrorMessage, getContractKitWithAgent, KEY_VERSION_HEADER, loggerMiddleware, @@ -8,7 +9,8 @@ import { OdisRequest, rootLogger, } from '@celo/phone-number-privacy-common' -import express, { RequestHandler } from 'express' +import express, { Express, RequestHandler } from 'express' +import httpProxy from 'http-proxy' import { Signer } from './common/combine' import { catchErrorHandler, @@ -28,7 +30,7 @@ import { pnpSign } from './pnp/endpoints/sign/action' require('events').EventEmitter.defaultMaxListeners = 15 -export function startCombiner(config: CombinerConfig, kit?: ContractKit) { +export function startCombiner(config: CombinerConfig, kit?: ContractKit): Express { const logger = rootLogger(config.serviceName) kit = kit ?? getContractKitWithAgent(config.blockchain) @@ -106,3 +108,49 @@ function createHandler( tracingHandler(meteringHandler(enabled ? resultHandler(action) : disabledHandler)) ) } + +export function startProxy(req: any, res: any, config: CombinerConfig) { + let destinationUrl + + const logger = rootLogger(config.serviceName) + logger.info('Starting proxy.') + const proxy = httpProxy.createProxyServer({ + proxyTimeout: config.phoneNumberPrivacy.odisServices.timeoutMilliSeconds, + }) + logger.info('created proxy server.') + + switch (config.proxy.deploymentEnv) { + case 'mainnet': + // XXX (soloseng):URL may need to be updated after gen2 function is created on mainnet + destinationUrl = 'https://us-central1-celo-pgpnp-mainnet.cloudfunctions.net/combinerGen2' + proxy.web(req, res, { target: destinationUrl }) + break + case 'alfajores': + // XXX (soloseng):URL may need to be updated after gen2 function is created on alfajores + destinationUrl = + 'https://us-central1-celo-phone-number-privacy.cloudfunctions.net/combinerGen2' + + proxy.web(req, res, { target: destinationUrl }) + break + case 'staging': + destinationUrl = + 'https://us-central1-celo-phone-number-privacy-stg.cloudfunctions.net/combinerGen2' + + logger.info( + { request: req, destinationURL: destinationUrl }, + 'Proxying request to staging Combiner gen 2.' + ) + + proxy.web(req, res, { target: destinationUrl }) + break + default: + throw ErrorMessage.UNKNOWN_ERROR + } + proxy.on('error', (err) => { + logger.error({ err }, 'Error in Proxying request to Combiner.') + res.status(500).json({ + success: false, + error: err, + }) + }) +} diff --git a/yarn.lock b/yarn.lock index 4f044aac7a3..234c19dd960 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6456,6 +6456,13 @@ resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz" integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== +"@types/http-proxy@^1.17.11": + version "1.17.12" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.12.tgz#86e849e9eeae0362548803c37a0a1afc616bd96b" + integrity sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw== + dependencies: + "@types/node" "*" + "@types/humanize-duration@^3.27.0": version "3.27.1" resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.1.tgz#f14740d1f585a0a8e3f46359b62fda8b0eaa31e7" @@ -12508,7 +12515,7 @@ eventemitter3@4.0.4: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== -eventemitter3@^4.0.4: +eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -13515,7 +13522,7 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" -follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.14.7, follow-redirects@^1.15.0: +follow-redirects@^1.0.0, follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.14.7, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -15302,6 +15309,15 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + http-response-object@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810"