Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

refactor: decrypt PK when it is used #858

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/bindings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
const {
baseMultiplier,
timeLabels,
privateKey,
privateKeyEncrypted,
priorityLabels,
incentives,
paymentPermitMaxPrice,
Expand Down Expand Up @@ -60,7 +60,7 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
payout: {
networkId: networkId,
rpc: rpc,
privateKey: privateKey,
privateKeyEncrypted: privateKeyEncrypted || "",
rndquu marked this conversation as resolved.
Show resolved Hide resolved
paymentToken: paymentToken,
permitBaseUrl: process.env.PERMIT_BASE_URL || permitBaseUrl,
},
Expand Down Expand Up @@ -113,7 +113,7 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
newContributorGreeting: newContributorGreeting,
};

if (botConfig.payout.privateKey == "") {
if (botConfig.payout.privateKeyEncrypted == "") {
botConfig.mode.paymentPermitMaxPrice = 0;
}

Expand Down
8 changes: 4 additions & 4 deletions src/handlers/payout/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface IncentivesCalculationResult {
paymentToken: string;
rpc: string;
networkId: number;
privateKey: string;
privateKeyEncrypted: string;
paymentPermitMaxPrice: number;
baseMultiplier: number;
incentives: Incentives;
Expand Down Expand Up @@ -66,7 +66,7 @@ export interface RewardByUser {
export const incentivesCalculation = async (): Promise<IncentivesCalculationResult> => {
const context = getBotContext();
const {
payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKey },
payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKeyEncrypted },
mode: { incentiveMode, paymentPermitMaxPrice },
price: { incentives, issueCreatorMultiplier, baseMultiplier },
accessControl,
Expand Down Expand Up @@ -147,7 +147,7 @@ export const incentivesCalculation = async (): Promise<IncentivesCalculationResu
throw new Error("No incentive mode. skipping to process");
}

if (privateKey == "") {
if (privateKeyEncrypted == "") {
logger.info("Permit generation disabled because wallet private key is not set.");
throw new Error("Permit generation disabled because wallet private key is not set.");
}
Expand Down Expand Up @@ -247,7 +247,7 @@ export const incentivesCalculation = async (): Promise<IncentivesCalculationResu
paymentToken,
rpc,
networkId,
privateKey,
privateKeyEncrypted,
recipient,
multiplier,
paymentPermitMaxPrice,
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/payout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const PAYMENT_TOKEN_PER_NETWORK: Record<string, { rpc: string; token: string }>
},
};

type PayoutConfigPartial = Omit<Static<typeof PayoutConfigSchema>, "networkId" | "privateKey" | "permitBaseUrl">;
type PayoutConfigPartial = Omit<Static<typeof PayoutConfigSchema>, "networkId" | "privateKeyEncrypted" | "permitBaseUrl">;

/**
* Returns payout config for a particular network
Expand Down
7 changes: 5 additions & 2 deletions src/helpers/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export type LogNotification = Static<typeof LogNotificationSchema>;
export const PayoutConfigSchema = Type.Object({
networkId: Type.Number(),
rpc: Type.String(),
privateKey: Type.String(),
privateKeyEncrypted: Type.String(),
paymentToken: Type.String(),
permitBaseUrl: Type.String(),
});
Expand Down
24 changes: 8 additions & 16 deletions src/utils/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | undefined> => {
Expand Down Expand Up @@ -64,17 +64,16 @@ export const getOrgAndRepoFromPath = (path: string) => {
return { org, repo };
};

export const getPrivateKey = async (cipherText: string): Promise<string | undefined> => {
export const getPrivateKey = async (cipherText: string): Promise<string> => {
try {
await _sodium.ready;
const sodium = _sodium;

const privateKey = process.env.X25519_PRIVATE_KEY;
const publicKey = await getScalarKey(privateKey);

if (!publicKey || !privateKey) {
return undefined;
}
if (!privateKey) throw new Error("X25519_PRIVATE_KEY env variable is missing");
if (!publicKey) throw new Error("Failed getting public key from X25519_PRIVATE_KEY env variable");

const binPub = sodium.from_base64(publicKey, sodium.base64_variants.URLSAFE_NO_PADDING);
const binPriv = sodium.from_base64(privateKey, sodium.base64_variants.URLSAFE_NO_PADDING);
Expand All @@ -84,7 +83,9 @@ export const getPrivateKey = async (cipherText: string): Promise<string | undefi
walletPrivateKey = walletPrivateKey.replace(KEY_PREFIX, "");
return walletPrivateKey;
} catch (error: unknown) {
return undefined;
const logger = getLogger();
logger.error(`${error}`);
throw new Error("Failed decrypting partner wallet private key");
}
};

Expand Down Expand Up @@ -136,21 +137,12 @@ export const getWideConfig = async (context: Context) => {
}
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,
Expand Down
Loading