Skip to content

Commit

Permalink
Store local wallet encrypted json in database (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-maj authored Oct 3, 2023
1 parent ba943ae commit e6b4fd2
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 61 deletions.
91 changes: 47 additions & 44 deletions server/utils/storage/localStorage.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,63 @@
import { AsyncStorage } from "@thirdweb-dev/wallets";
import * as fs from "fs";
import fs from "fs";
import { prisma } from "../../../src/db/client";
import { WalletType } from "../../../src/schema/wallet";
import { logger } from "../../../src/utils/logger";

export class LocalFileStorage implements AsyncStorage {
constructor(private readonly walletAddress?: string) {
if (walletAddress) {
this.walletAddress = walletAddress;
}
constructor(private readonly walletAddress: string) {
this.walletAddress = walletAddress.toLowerCase();
}

getKey(): string {
if (this.walletAddress) {
return `localWallet-${this.walletAddress.toLowerCase()}`;
async getItem(_: string): Promise<string | null> {
const walletDetails = await prisma.walletDetails.findUnique({
where: {
address: this.walletAddress,
},
});

if (walletDetails?.encryptedJson) {
return walletDetails.encryptedJson;
}
throw new Error("Wallet Address not set");
}

getItem(_: string): Promise<string | null> {
//read file from home directory/.thirdweb folder
//file name is the key name
//return null if it doesn't exist
//return the value if it does exist
// For backwards compatibility, support old local file storage format
const dir = `${process.env.HOME}/.thirdweb`;
if (!fs.existsSync(dir)) {
return Promise.resolve(null);
const path = `${dir}/localWallet-${this.walletAddress}`;
if (!fs.existsSync(dir) || !fs.existsSync(path)) {
logger.worker.error(`No local wallet found!`);
return null;
}

const path = `${dir}/${this.getKey()}`;
if (!fs.existsSync(path)) {
return Promise.resolve(null);
}
return Promise.resolve(fs.readFileSync(path, "utf8"));
// Save the encrypted json in the database for future access
const encryptedJson = fs.readFileSync(path, "utf8");
await this.setItem("", encryptedJson);

return encryptedJson;
}

setItem(_: string, value: string): Promise<void> {
//save to home directory .thirdweb folder
//create the folder if it doesn't exist
const dir = `${process.env.HOME}/.thirdweb`;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
fs.writeFileSync(`${dir}/${this.getKey()}`, value);
return Promise.resolve();
async setItem(_: string, value: string): Promise<void> {
await prisma.walletDetails.upsert({
where: {
address: this.walletAddress,
type: WalletType.local,
},
create: {
address: this.walletAddress,
type: WalletType.local,
encryptedJson: value,
},
update: {
encryptedJson: value,
},
});
}

removeItem(_: string): Promise<void> {
//delete the file from home directory/.thirdweb folder
const dir = `${process.env.HOME}/.thirdweb`;
if (!fs.existsSync(dir)) {
return Promise.resolve();
}
const path = `${dir}/${this.getKey()}`;
if (!fs.existsSync(path)) {
return Promise.resolve();
} else {
fs.unlinkSync(path);
return Promise.resolve();
}
async removeItem(_: string): Promise<void> {
await prisma.walletDetails.delete({
where: {
address: this.walletAddress,
type: WalletType.local,
},
});
}
}
8 changes: 1 addition & 7 deletions server/utils/wallets/createLocalWallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LocalWallet } from "@thirdweb-dev/wallets";
import { createWalletDetails } from "../../../src/db/wallets/createWalletDetails";
import { WalletType } from "../../../src/schema/wallet";
import { env } from "../../../src/utils/env";
import { LocalFileStorage } from "../storage/localStorage";
Expand All @@ -12,17 +11,12 @@ export const createLocalWallet = async (): Promise<string> => {
const wallet = new LocalWallet();
const walletAddress = await wallet.generate();

// TODO: File storage should use postgres and be instantiated with local wallet
// Creating wallet details row is handled by LocalFileStorage
await wallet.save({
strategy: "encryptedJson",
password: env.THIRDWEB_API_SECRET_KEY,
storage: new LocalFileStorage(walletAddress),
});

await createWalletDetails({
type: WalletType.local,
address: walletAddress,
});

return walletAddress;
};
8 changes: 1 addition & 7 deletions server/utils/wallets/importLocalWallet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { LocalWallet } from "@thirdweb-dev/wallets";
import { createWalletDetails } from "../../../src/db/wallets/createWalletDetails";
import { WalletType } from "../../../src/schema/wallet";
import { env } from "../../../src/utils/env";
import { LocalFileStorage } from "../storage/localStorage";

Expand Down Expand Up @@ -47,16 +45,12 @@ export const importLocalWallet = async (
break;
}

// Creating wallet details gets handled by LocalFileStorage
await wallet.save({
strategy: "encryptedJson",
password: env.THIRDWEB_API_SECRET_KEY,
storage: new LocalFileStorage(walletAddress),
});

await createWalletDetails({
address: walletAddress,
type: WalletType.local,
});

return walletAddress;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "wallet_details" ADD COLUMN "encryptedJson" TEXT;
8 changes: 5 additions & 3 deletions src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ generator client {
model WalletDetails {
address String @id @map("address")
type String @map("type")
// Local
encryptedJson String? @map("encryptedJson")
// KMS
awsKmsKeyId String? @map("awsKmsKeyId")
awsKmsArn String? @map("awsKmsArn")
Expand Down Expand Up @@ -88,8 +90,8 @@ model Transactions {
}

model CancelledTransactions {
queueId String @id @map("queueId")
cancelledByWorkerAt DateTime? @map("cancelledByWorkerAt")
queueId String @id @map("queueId")
cancelledByWorkerAt DateTime? @map("cancelledByWorkerAt")
@@map("cancelled_transactions")
}
}

0 comments on commit e6b4fd2

Please sign in to comment.