From f89c8f758ece7ddcc082d62b5994ecdcc0104cbe Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Wed, 6 Nov 2024 19:51:14 +0530 Subject: [PATCH] setup foundations --- src/db/configuration/getConfiguration.ts | 30 ++++++++++++++ src/db/configuration/updateConfiguration.ts | 35 +++++++++++----- src/prisma/schema.prisma | 46 ++++++++++++--------- src/schema/config.ts | 3 ++ 4 files changed, 85 insertions(+), 29 deletions(-) diff --git a/src/db/configuration/getConfiguration.ts b/src/db/configuration/getConfiguration.ts index 67c47f9a6..0f1ae5227 100644 --- a/src/db/configuration/getConfiguration.ts +++ b/src/db/configuration/getConfiguration.ts @@ -3,6 +3,7 @@ import type { Static } from "@sinclair/typebox"; import { LocalWallet } from "@thirdweb-dev/wallets"; import { ethers } from "ethers"; import type { Chain } from "thirdweb"; +import { z } from "zod"; import type { AwsWalletConfiguration, GcpWalletConfiguration, @@ -17,6 +18,17 @@ import { logger } from "../../utils/logger"; import { prisma } from "../client"; import { updateConfiguration } from "./updateConfiguration"; +const circleCredentialSchema = z.object({ + apiKey: z.string(), + entitySecret: z.string(), +}); + +export type CircleCredential = z.infer; + +export const walletProviderCredentialsSchema = z.object({ + cirlce: circleCredentialSchema.optional(), +}); + const toParsedConfig = async (config: Configuration): Promise => { // We destructure the config to omit wallet related fields to prevent direct access const { @@ -29,6 +41,7 @@ const toParsedConfig = async (config: Configuration): Promise => { gcpApplicationCredentialEmail, gcpApplicationCredentialPrivateKey, contractSubscriptionsRetryDelaySeconds, + walletProviderCredentials, ...restConfig } = config; @@ -162,6 +175,22 @@ const toParsedConfig = async (config: Configuration): Promise => { legacyWalletType_removeInNextBreakingChange = WalletType.gcpKms; } + const otherCredentials = walletProviderCredentialsSchema.parse( + walletProviderCredentials, + ); + + let circleCredentials: CircleCredential | null = null; + + if (otherCredentials.cirlce) { + circleCredentials = { + apiKey: otherCredentials.cirlce.apiKey, + entitySecret: decrypt( + otherCredentials.cirlce.entitySecret, + env.ENCRYPTION_PASSWORD, + ), + }; + } + return { ...restConfig, contractSubscriptionsRequeryDelaySeconds: @@ -170,6 +199,7 @@ const toParsedConfig = async (config: Configuration): Promise => { walletConfiguration: { aws: awsWalletConfiguration, gcp: gcpWalletConfiguration, + circle: circleCredentials, legacyWalletType_removeInNextBreakingChange, }, }; diff --git a/src/db/configuration/updateConfiguration.ts b/src/db/configuration/updateConfiguration.ts index f6d14fd47..3ed040c2c 100644 --- a/src/db/configuration/updateConfiguration.ts +++ b/src/db/configuration/updateConfiguration.ts @@ -1,26 +1,41 @@ import type { Prisma } from "@prisma/client"; import { encrypt } from "../../utils/crypto"; import { prisma } from "../client"; +import { walletProviderCredentialsSchema } from "./getConfiguration"; export const updateConfiguration = async ( data: Prisma.ConfigurationUpdateArgs["data"], ) => { + // ecnrypt AWS credential data + if (typeof data.awsSecretAccessKey === "string") { + data.awsSecretAccessKey = encrypt(data.awsSecretAccessKey); + } + + // ecnrypt GCP credential data + if (typeof data.gcpApplicationCredentialPrivateKey === "string") { + data.gcpApplicationCredentialPrivateKey = encrypt( + data.gcpApplicationCredentialPrivateKey, + ); + } + + const walletProviderCredentials = walletProviderCredentialsSchema.parse( + data.walletProviderCredentials, + ); + + // Encrypt Circle credential data + if (walletProviderCredentials.cirlce) { + walletProviderCredentials.cirlce.entitySecret = encrypt( + walletProviderCredentials.cirlce.entitySecret, + ); + } + return prisma.configuration.update({ where: { id: "default", }, data: { ...data, - ...(typeof data.awsSecretAccessKey === "string" - ? { awsSecretAccessKey: encrypt(data.awsSecretAccessKey) } - : {}), - ...(typeof data.gcpApplicationCredentialPrivateKey === "string" - ? { - gcpApplicationCredentialPrivateKey: encrypt( - data.gcpApplicationCredentialPrivateKey, - ), - } - : {}), + walletProviderCredentials, }, }); }; diff --git a/src/prisma/schema.prisma b/src/prisma/schema.prisma index 2ae38f162..fbd7cbe13 100644 --- a/src/prisma/schema.prisma +++ b/src/prisma/schema.prisma @@ -30,26 +30,30 @@ model Configuration { contractSubscriptionsRetryDelaySeconds String @default("10") @map("contractSubscriptionsRetryDelaySeconds") // AWS - awsAccessKeyId String? @map("awsAccessKeyId") /// global config, precedence goes to WalletDetails - awsSecretAccessKey String? @map("awsSecretAccessKey") /// global config, precedence goes to WalletDetails - awsRegion String? @map("awsRegion") /// global config, treat as "default", store in WalletDetails.awsKmsArn + awsAccessKeyId String? @map("awsAccessKeyId") /// global config, precedence goes to WalletDetails + awsSecretAccessKey String? @map("awsSecretAccessKey") /// global config, precedence goes to WalletDetails + awsRegion String? @map("awsRegion") /// global config, treat as "default", store in WalletDetails.awsKmsArn // GCP - gcpApplicationProjectId String? @map("gcpApplicationProjectId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath - gcpKmsLocationId String? @map("gcpKmsLocationId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath - gcpKmsKeyRingId String? @map("gcpKmsKeyRingId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath - gcpApplicationCredentialEmail String? @map("gcpApplicationCredentialEmail") /// global config, precedence goes to WalletDetails - gcpApplicationCredentialPrivateKey String? @map("gcpApplicationCredentialPrivateKey") /// global config, precedence goes to WalletDetails + gcpApplicationProjectId String? @map("gcpApplicationProjectId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath + gcpKmsLocationId String? @map("gcpKmsLocationId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath + gcpKmsKeyRingId String? @map("gcpKmsKeyRingId") /// global config, treat as "default", store in WalletDetails.gcpKmsResourcePath + gcpApplicationCredentialEmail String? @map("gcpApplicationCredentialEmail") /// global config, precedence goes to WalletDetails + gcpApplicationCredentialPrivateKey String? @map("gcpApplicationCredentialPrivateKey") /// global config, precedence goes to WalletDetails + + // other wallet provider credentials + walletProviderCredentials Json @default("{}") @map("walletProviderCredentials") /// GCP and AWS credentials are stored as rows in WalletDetails, but other providers are stored here + // Auth - authDomain String @default("") @map("authDomain") // TODO: Remove defaults on major - authWalletEncryptedJson String @default("") @map("authWalletEncryptedJson") // TODO: Remove defaults on major + authDomain String @default("") @map("authDomain") // TODO: Remove defaults on major + authWalletEncryptedJson String @default("") @map("authWalletEncryptedJson") // TODO: Remove defaults on major // Webhook - webhookUrl String? @map("webhookUrl") - webhookAuthBearerToken String? @map("webhookAuthBearerToken") + webhookUrl String? @map("webhookUrl") + webhookAuthBearerToken String? @map("webhookAuthBearerToken") // Wallet balance - minWalletBalance String @default("20000000000000000") @map("minWalletBalance") - accessControlAllowOrigin String @default("https://thirdweb.com,https://embed.ipfscdn.io") @map("accessControlAllowOrigin") - ipAllowlist String[] @default([]) @map("ipAllowlist") - clearCacheCronSchedule String @default("*/30 * * * * *") @map("clearCacheCronSchedule") + minWalletBalance String @default("20000000000000000") @map("minWalletBalance") + accessControlAllowOrigin String @default("https://thirdweb.com,https://embed.ipfscdn.io") @map("accessControlAllowOrigin") + ipAllowlist String[] @default([]) @map("ipAllowlist") + clearCacheCronSchedule String @default("*/30 * * * * *") @map("clearCacheCronSchedule") @@map("configuration") } @@ -94,10 +98,14 @@ model WalletDetails { gcpKmsResourcePath String? @map("gcpKmsResourcePath") @db.Text gcpApplicationCredentialEmail String? @map("gcpApplicationCredentialEmail") /// if not available, default to: Configuration.gcpApplicationCredentialEmail gcpApplicationCredentialPrivateKey String? @map("gcpApplicationCredentialPrivateKey") /// if not available, default to: Configuration.gcpApplicationCredentialPrivateKey + + // other types of credentials + credentials Json? @map("credentials") + // Smart Backend Wallet - accountSignerAddress String? @map("accountSignerAddress") /// this, and either local, aws or gcp encryptedJson, are required for smart wallet - accountFactoryAddress String? @map("accountFactoryAddress") /// optional even for smart wallet, if not available default factory will be used - entrypointAddress String? @map("entrypointAddress") /// optional even for smart wallet, if not available SDK will use default entrypoint + accountSignerAddress String? @map("accountSignerAddress") /// this, and either local, aws or gcp encryptedJson, are required for smart wallet + accountFactoryAddress String? @map("accountFactoryAddress") /// optional even for smart wallet, if not available default factory will be used + entrypointAddress String? @map("entrypointAddress") /// optional even for smart wallet, if not available SDK will use default entrypoint @@map("wallet_details") } diff --git a/src/schema/config.ts b/src/schema/config.ts index fc3ce2d62..b564b3d04 100644 --- a/src/schema/config.ts +++ b/src/schema/config.ts @@ -1,5 +1,6 @@ import type { Configuration } from "@prisma/client"; import type { Chain } from "thirdweb"; +import type { CircleCredential } from "../db/configuration/getConfiguration"; import type { WalletType } from "./wallet"; export type AwsWalletConfiguration = { @@ -32,11 +33,13 @@ export interface ParsedConfig | "gcpKmsKeyRingId" | "gcpApplicationCredentialEmail" | "gcpApplicationCredentialPrivateKey" + | "walletProviderCredentials" | "contractSubscriptionsRetryDelaySeconds" > { walletConfiguration: { aws: AwsWalletConfiguration | null; gcp: GcpWalletConfiguration | null; + circle: CircleCredential | null; legacyWalletType_removeInNextBreakingChange: WalletType; }; contractSubscriptionsRequeryDelaySeconds: string;