From 0a26b93f344c03e77df9987cbfdcfd6b983d755a Mon Sep 17 00:00:00 2001 From: rndquu Date: Fri, 13 Oct 2023 10:59:24 +0300 Subject: [PATCH 1/2] refactor: decrypt PK when it is used --- src/bindings/config.ts | 6 +++--- src/handlers/payout/action.ts | 8 ++++---- src/helpers/payout.ts | 2 +- src/helpers/permit.ts | 7 +++++-- src/types/config.ts | 2 +- src/utils/private.ts | 24 ++++++++---------------- 6 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/bindings/config.ts b/src/bindings/config.ts index 43b5718fa..5a2c0841d 100644 --- a/src/bindings/config.ts +++ b/src/bindings/config.ts @@ -10,7 +10,7 @@ export const loadConfig = async (context: Context): Promise => { const { baseMultiplier, timeLabels, - privateKey, + privateKeyEncrypted, priorityLabels, incentives, paymentPermitMaxPrice, @@ -60,7 +60,7 @@ export const loadConfig = async (context: Context): Promise => { payout: { networkId: networkId, rpc: rpc, - privateKey: privateKey, + privateKeyEncrypted: privateKeyEncrypted || "", paymentToken: paymentToken, permitBaseUrl: process.env.PERMIT_BASE_URL || permitBaseUrl, }, @@ -113,7 +113,7 @@ export const loadConfig = async (context: Context): Promise => { newContributorGreeting: newContributorGreeting, }; - if (botConfig.payout.privateKey == "") { + if (botConfig.payout.privateKeyEncrypted == "") { botConfig.mode.paymentPermitMaxPrice = 0; } diff --git a/src/handlers/payout/action.ts b/src/handlers/payout/action.ts index 25bf01562..924bcc724 100644 --- a/src/handlers/payout/action.ts +++ b/src/handlers/payout/action.ts @@ -27,7 +27,7 @@ export interface IncentivesCalculationResult { paymentToken: string; rpc: string; networkId: number; - privateKey: string; + privateKeyEncrypted: string; paymentPermitMaxPrice: number; baseMultiplier: number; incentives: Incentives; @@ -66,7 +66,7 @@ export interface RewardByUser { export const incentivesCalculation = async (): Promise => { const context = getBotContext(); const { - payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKey }, + payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKeyEncrypted }, mode: { incentiveMode, paymentPermitMaxPrice }, price: { incentives, issueCreatorMultiplier, baseMultiplier }, accessControl, @@ -147,7 +147,7 @@ export const incentivesCalculation = async (): Promise }, }; -type PayoutConfigPartial = Omit, "networkId" | "privateKey" | "permitBaseUrl">; +type PayoutConfigPartial = Omit, "networkId" | "privateKeyEncrypted" | "permitBaseUrl">; /** * Returns payout config for a particular network diff --git a/src/helpers/permit.ts b/src/helpers/permit.ts index deddcffe0..a0849529e 100644 --- a/src/helpers/permit.ts +++ b/src/helpers/permit.ts @@ -5,6 +5,7 @@ import { keccak256, toUtf8Bytes } from "ethers/lib/utils"; import Decimal from "decimal.js"; import { Payload } from "../types"; import { savePermit } from "../adapters/supabase"; +import { getPrivateKey } from "../utils/private"; const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on all networks @@ -59,11 +60,13 @@ export const generatePermit2Signature = async ( userId = "" ): Promise<{ txData: TxData; payoutUrl: string }> => { const { - payout: { networkId, privateKey, permitBaseUrl, rpc, paymentToken }, + payout: { networkId, privateKeyEncrypted, permitBaseUrl, rpc, paymentToken }, } = getBotConfig(); const logger = getLogger(); const provider = new ethers.providers.JsonRpcProvider(rpc); - const adminWallet = new ethers.Wallet(privateKey, provider); + + const privateKeyDecrypted = await getPrivateKey(privateKeyEncrypted); + const adminWallet = new ethers.Wallet(privateKeyDecrypted, provider); const permitTransferFromData: PermitTransferFrom = { permitted: { diff --git a/src/types/config.ts b/src/types/config.ts index a22683a28..4a8c97093 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -76,7 +76,7 @@ export type LogNotification = Static; export const PayoutConfigSchema = Type.Object({ networkId: Type.Number(), rpc: Type.String(), - privateKey: Type.String(), + privateKeyEncrypted: Type.String(), paymentToken: Type.String(), permitBaseUrl: Type.String(), }); diff --git a/src/utils/private.ts b/src/utils/private.ts index 44ba7fb15..423ce7ea3 100644 --- a/src/utils/private.ts +++ b/src/utils/private.ts @@ -8,10 +8,10 @@ import { DefaultConfig } from "../configs"; import { validate } from "./ajv"; import { WideConfig, WideRepoConfig, WideConfigSchema } from "../types"; import { upsertLastCommentToIssue } from "../helpers"; +import { getLogger } from "../bindings"; const CONFIG_REPO = "ubiquibot-config"; const CONFIG_PATH = ".github/ubiquibot-config.yml"; -const KEY_NAME = "privateKeyEncrypted"; const KEY_PREFIX = "HSK_"; export const getConfigSuperset = async (context: Context, type: "org" | "repo", filePath: string): Promise => { @@ -64,7 +64,7 @@ export const getOrgAndRepoFromPath = (path: string) => { return { org, repo }; }; -export const getPrivateKey = async (cipherText: string): Promise => { +export const getPrivateKey = async (cipherText: string): Promise => { try { await _sodium.ready; const sodium = _sodium; @@ -72,9 +72,8 @@ export const getPrivateKey = async (cipherText: string): Promise { } const parsedDefault: MergedConfig = DefaultConfig; - let privateKeyDecrypted; - if (parsedRepo && parsedRepo[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedRepo[KEY_NAME]); - } else if (parsedOrg && parsedOrg[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedOrg[KEY_NAME]); - } else { - privateKeyDecrypted = undefined; - } - const configs: MergedConfigs = { parsedDefault, parsedOrg, parsedRepo }; const mergedConfigData: MergedConfig = mergeConfigs(configs); const configData = { networkId: mergedConfigData.evmNetworkId, - privateKey: privateKeyDecrypted ?? "", + privateKeyEncrypted: mergedConfigData.privateKeyEncrypted, assistivePricing: mergedConfigData.assistivePricing, commandSettings: mergedConfigData.commandSettings, baseMultiplier: mergedConfigData.priceMultiplier, From 9c587460af1b92cadaa2d50ca524e3c1c652dc14 Mon Sep 17 00:00:00 2001 From: rndquu Date: Tue, 17 Oct 2023 01:42:03 +0300 Subject: [PATCH 2/2] refactor: make privateKeyEncrypted nullable --- src/bindings/config.ts | 4 ++-- src/handlers/payout/action.ts | 4 ++-- src/types/config.ts | 2 +- src/utils/private.ts | 4 +++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bindings/config.ts b/src/bindings/config.ts index 5a2c0841d..4599436ef 100644 --- a/src/bindings/config.ts +++ b/src/bindings/config.ts @@ -60,7 +60,7 @@ export const loadConfig = async (context: Context): Promise => { payout: { networkId: networkId, rpc: rpc, - privateKeyEncrypted: privateKeyEncrypted || "", + privateKeyEncrypted: privateKeyEncrypted || null, paymentToken: paymentToken, permitBaseUrl: process.env.PERMIT_BASE_URL || permitBaseUrl, }, @@ -113,7 +113,7 @@ export const loadConfig = async (context: Context): Promise => { newContributorGreeting: newContributorGreeting, }; - if (botConfig.payout.privateKeyEncrypted == "") { + if (!botConfig.payout.privateKeyEncrypted) { botConfig.mode.paymentPermitMaxPrice = 0; } diff --git a/src/handlers/payout/action.ts b/src/handlers/payout/action.ts index 924bcc724..9f996de40 100644 --- a/src/handlers/payout/action.ts +++ b/src/handlers/payout/action.ts @@ -27,7 +27,7 @@ export interface IncentivesCalculationResult { paymentToken: string; rpc: string; networkId: number; - privateKeyEncrypted: string; + privateKeyEncrypted: string | null; paymentPermitMaxPrice: number; baseMultiplier: number; incentives: Incentives; @@ -147,7 +147,7 @@ export const incentivesCalculation = async (): Promise; export const PayoutConfigSchema = Type.Object({ networkId: Type.Number(), rpc: Type.String(), - privateKeyEncrypted: Type.String(), + privateKeyEncrypted: Type.Union([Type.Null(), Type.String()]), paymentToken: Type.String(), permitBaseUrl: Type.String(), }); diff --git a/src/utils/private.ts b/src/utils/private.ts index 423ce7ea3..57db827db 100644 --- a/src/utils/private.ts +++ b/src/utils/private.ts @@ -64,8 +64,10 @@ export const getOrgAndRepoFromPath = (path: string) => { return { org, repo }; }; -export const getPrivateKey = async (cipherText: string): Promise => { +export const getPrivateKey = async (cipherText: string | null): Promise => { try { + if (!cipherText) throw new Error("Cipher text is empty"); + await _sodium.ready; const sodium = _sodium;