Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional labels to wallets, permissions, tokens, and webhooks #260

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 9 additions & 1 deletion server/api/auth/access-tokens/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { createToken } from "../../../../src/db/tokens/createToken";
import { env } from "../../../../src/utils/env";
import { AccessTokenSchema } from "./getAll";

const BodySchema = Type.Object({
label: Type.Optional(Type.String()),
});

const ReplySchema = Type.Object({
result: Type.Composite([
AccessTokenSchema,
Expand All @@ -19,6 +23,7 @@ const ReplySchema = Type.Object({

export async function createAccessToken(fastify: FastifyInstance) {
fastify.route<{
Body: Static<typeof BodySchema>;
Reply: Static<typeof ReplySchema>;
}>({
method: "POST",
Expand All @@ -28,11 +33,14 @@ export async function createAccessToken(fastify: FastifyInstance) {
description: "Create a new access token",
tags: ["Access Tokens"],
operationId: "createAccessToken",
body: BodySchema,
response: {
[StatusCodes.OK]: ReplySchema,
},
},
handler: async (req, res) => {
const { label } = req.body;

const config = await getConfiguration();
const wallet = new LocalWallet();
await wallet.import({
Expand All @@ -54,7 +62,7 @@ export async function createAccessToken(fastify: FastifyInstance) {
},
});

const token = await createToken({ jwt, isAccessToken: true });
const token = await createToken({ jwt, isAccessToken: true, label });

res.status(200).send({
result: {
Expand Down
1 change: 1 addition & 0 deletions server/api/auth/access-tokens/getAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const AccessTokenSchema = Type.Object({
walletAddress: Type.String(),
createdAt: Type.String(),
expiresAt: Type.String(),
label: Type.Union([Type.String(), Type.Null()]),
});

const ReplySchema = Type.Object({
Expand Down
1 change: 1 addition & 0 deletions server/api/auth/permissions/getAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ReplySchema = Type.Object({
Type.Object({
walletAddress: Type.String(),
permissions: Type.String(),
label: Type.Union([Type.String(), Type.Null()]),
}),
),
});
Expand Down
4 changes: 3 additions & 1 deletion server/api/auth/permissions/grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PermissionsSchema } from "../../../schemas/auth";
const BodySchema = Type.Object({
walletAddress: Type.String(),
permissions: PermissionsSchema,
label: Type.Optional(Type.String()),
});

const ReplySchema = Type.Object({
Expand All @@ -33,10 +34,11 @@ export async function grantPermissions(fastify: FastifyInstance) {
},
},
handler: async (req, res) => {
const { walletAddress, permissions } = req.body;
const { walletAddress, permissions, label } = req.body;
await updatePermissions({
walletAddress,
permissions,
label,
});
res.status(200).send({
result: {
Expand Down
17 changes: 12 additions & 5 deletions server/api/backend-wallet/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { createAwsKmsWallet } from "../../utils/wallets/createAwsKmsWallet";
import { createGcpKmsWallet } from "../../utils/wallets/createGcpKmsWallet";
import { createLocalWallet } from "../../utils/wallets/createLocalWallet";

// OUTPUT
const BodySchema = Type.Object({
label: Type.Optional(Type.String()),
});

const responseSchema = Type.Object({
result: Type.Object({
walletAddress: Type.String(),
Expand All @@ -25,6 +28,7 @@ responseSchema.example = {

export const createWallet = async (fastify: FastifyInstance) => {
fastify.route<{
Body: Static<typeof BodySchema>;
Reply: Static<typeof responseSchema>;
}>({
method: "POST",
Expand All @@ -34,23 +38,26 @@ export const createWallet = async (fastify: FastifyInstance) => {
description: "Create a backend wallet.",
tags: ["Backend Wallet"],
operationId: "backendWallet_create",
body: BodySchema,
response: {
...standardResponseSchema,
[StatusCodes.OK]: responseSchema,
},
},
handler: async (request, reply) => {
handler: async (req, reply) => {
const { label } = req.body;

let walletAddress: string;
const config = await getConfiguration();
switch (config.walletConfiguration.type) {
case WalletType.local:
walletAddress = await createLocalWallet();
walletAddress = await createLocalWallet({ label });
break;
case WalletType.awsKms:
walletAddress = await createAwsKmsWallet();
walletAddress = await createAwsKmsWallet({ label });
break;
case WalletType.gcpKms:
walletAddress = await createGcpKmsWallet();
walletAddress = await createGcpKmsWallet({ label });
break;
}

Expand Down
1 change: 1 addition & 0 deletions server/api/backend-wallet/getAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ responseSchema.example = {
{
address: "0xe201a491a204e4a78e60033ae8ed39036b55bacb",
type: "local",
label: "my-wallet",
awsKmsKeyId: null,
awsKmsArn: null,
gcpKmsKeyId: null,
Expand Down
8 changes: 5 additions & 3 deletions server/api/webhooks/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ const BodySchema = Type.Object({
"https://example.com/webhooks",
],
}),
name: Type.String({
minLength: 5,
}),
name: Type.Optional(
Type.String({
minLength: 5,
}),
),
eventType: Type.Enum(WebhooksEventTypes),
});

Expand Down
2 changes: 1 addition & 1 deletion server/api/webhooks/getAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ReplySchema = Type.Object({
result: Type.Array(
Type.Object({
url: Type.String(),
name: Type.String(),
name: Type.Union([Type.String(), Type.Null()]),
secret: Type.Optional(Type.String()),
eventType: Type.String(),
active: Type.Boolean(),
Expand Down
6 changes: 6 additions & 0 deletions server/helpers/sharedApiSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ export const walletDetailsSchema = Type.Object({
type: Type.String({
description: "Wallet Type",
}),
label: Type.Union([
Type.String({
description: "A label for your wallet",
}),
Type.Null(),
]),
awsKmsKeyId: Type.Union([
Type.String({
description: "AWS KMS Key ID",
Expand Down
7 changes: 6 additions & 1 deletion server/utils/storage/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { WalletType } from "../../../src/schema/wallet";
import { logger } from "../../../src/utils/logger";

export class LocalFileStorage implements AsyncStorage {
constructor(private readonly walletAddress: string) {
label?: string;

constructor(private readonly walletAddress: string, label?: string) {
this.walletAddress = walletAddress.toLowerCase();
this.label = label;
}

async getItem(_: string): Promise<string | null> {
Expand Down Expand Up @@ -45,9 +48,11 @@ export class LocalFileStorage implements AsyncStorage {
address: this.walletAddress,
type: WalletType.local,
encryptedJson: value,
label: this.label,
},
update: {
encryptedJson: value,
label: this.label,
},
});
}
Expand Down
10 changes: 8 additions & 2 deletions server/utils/wallets/createAwsKmsWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { getConfiguration } from "../../../src/db/configuration/getConfiguration
import { WalletType } from "../../../src/schema/wallet";
import { importAwsKmsWallet } from "./importAwsKmsWallet";

export const createAwsKmsWallet = async (): Promise<string> => {
interface CreateAwsKmsWalletParams {
label?: string;
}

export const createAwsKmsWallet = async ({
label,
}: CreateAwsKmsWalletParams): Promise<string> => {
const config = await getConfiguration();
if (config.walletConfiguration.type !== WalletType.awsKms) {
throw new Error(`Server was not configured for AWS KMS wallet creation`);
Expand All @@ -29,5 +35,5 @@ export const createAwsKmsWallet = async (): Promise<string> => {
const awsKmsArn = res.KeyMetadata!.Arn!;
const awsKmsKeyId = res.KeyMetadata!.KeyId!;

return importAwsKmsWallet({ awsKmsArn, awsKmsKeyId });
return importAwsKmsWallet({ awsKmsArn, awsKmsKeyId, label });
};
9 changes: 8 additions & 1 deletion server/utils/wallets/createGcpKmsWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { createWalletDetails } from "../../../src/db/wallets/createWalletDetails
import { WalletType } from "../../../src/schema/wallet";
import { getGcpKmsWallet } from "./getGcpKmsWallet";

export const createGcpKmsWallet = async (): Promise<string> => {
interface CreateGcpKmsWallet {
label?: string;
}

export const createGcpKmsWallet = async ({
label,
}: CreateGcpKmsWallet): Promise<string> => {
const config = await getConfiguration();
if (config.walletConfiguration.type !== WalletType.gcpKms) {
throw new Error(`Server was not configured for GCP KMS wallet creation`);
Expand Down Expand Up @@ -49,6 +55,7 @@ export const createGcpKmsWallet = async (): Promise<string> => {
await createWalletDetails({
type: WalletType.gcpKms,
address: walletAddress,
label,
gcpKmsKeyId: cryptoKeyId,
gcpKmsKeyRingId: config.walletConfiguration.gcpKmsKeyRingId,
gcpKmsLocationId: config.walletConfiguration.gcpKmsLocationId,
Expand Down
10 changes: 8 additions & 2 deletions server/utils/wallets/createLocalWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { WalletType } from "../../../src/schema/wallet";
import { env } from "../../../src/utils/env";
import { LocalFileStorage } from "../storage/localStorage";

export const createLocalWallet = async (): Promise<string> => {
interface CreateLocalWallet {
label?: string;
}

export const createLocalWallet = async ({
label,
}: CreateLocalWallet): Promise<string> => {
const config = await getConfiguration();
if (config.walletConfiguration.type !== WalletType.local) {
throw new Error(`Server was not configured for local wallet creation.`);
Expand All @@ -17,7 +23,7 @@ export const createLocalWallet = async (): Promise<string> => {
await wallet.save({
strategy: "encryptedJson",
password: env.THIRDWEB_API_SECRET_KEY,
storage: new LocalFileStorage(walletAddress),
storage: new LocalFileStorage(walletAddress, label),
});

return walletAddress;
Expand Down
3 changes: 3 additions & 0 deletions server/utils/wallets/importAwsKmsWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { getAwsKmsWallet } from "./getAwsKmsWallet";
interface ImportAwsKmsWalletParams {
awsKmsKeyId: string;
awsKmsArn: string;
label?: string;
}

export const importAwsKmsWallet = async ({
awsKmsKeyId,
awsKmsArn,
label,
}: ImportAwsKmsWalletParams) => {
const config = await getConfiguration();
if (config.walletConfiguration.type !== WalletType.awsKms) {
Expand All @@ -25,6 +27,7 @@ export const importAwsKmsWallet = async ({
address: walletAddress,
awsKmsArn,
awsKmsKeyId,
label,
});

return walletAddress;
Expand Down
3 changes: 3 additions & 0 deletions server/utils/wallets/importGcpKmsWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { getGcpKmsWallet } from "./getGcpKmsWallet";
interface ImportGcpKmsWalletParams {
gcpKmsKeyId: string;
gcpKmsKeyVersionId: string;
label?: string;
}

export const importGcpKmsWallet = async ({
gcpKmsKeyId,
gcpKmsKeyVersionId,
label,
}: ImportGcpKmsWalletParams) => {
const config = await getConfiguration();
if (config.walletConfiguration.type !== WalletType.gcpKms) {
Expand All @@ -24,6 +26,7 @@ export const importGcpKmsWallet = async ({
await createWalletDetails({
type: WalletType.gcpKms,
address: walletAddress,
label,
gcpKmsKeyId: gcpKmsKeyId,
gcpKmsKeyRingId: config.walletConfiguration.gcpKmsKeyRingId,
gcpKmsLocationId: config.walletConfiguration.gcpKmsLocationId,
Expand Down
5 changes: 4 additions & 1 deletion server/utils/wallets/importLocalWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ type ImportLocalWalletParams =
| {
method: "privateKey";
privateKey: string;
label?: string;
}
| {
method: "mnemonic";
mnemonic: string;
label?: string;
}
| {
method: "encryptedJson";
encryptedJson: string;
password: string;
label?: string;
};

export const importLocalWallet = async (
Expand Down Expand Up @@ -49,7 +52,7 @@ export const importLocalWallet = async (
await wallet.save({
strategy: "encryptedJson",
password: env.THIRDWEB_API_SECRET_KEY,
storage: new LocalFileStorage(walletAddress),
storage: new LocalFileStorage(walletAddress, options.label),
});

return walletAddress;
Expand Down
4 changes: 4 additions & 0 deletions src/db/permissions/updatePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { prisma } from "../client";
interface CreatePermissionsParams {
walletAddress: string;
permissions: string;
label?: string;
}

export const updatePermissions = async ({
walletAddress,
permissions,
label,
}: CreatePermissionsParams) => {
return prisma.permissions.upsert({
where: {
Expand All @@ -16,9 +18,11 @@ export const updatePermissions = async ({
create: {
walletAddress: walletAddress.toLowerCase(),
permissions,
label,
},
update: {
permissions,
label,
},
});
};
3 changes: 3 additions & 0 deletions src/db/tokens/createToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { prisma } from "../client";
interface CreateTokenParams {
jwt: string;
isAccessToken: boolean;
label?: string;
}

export const createToken = async ({
jwt,
isAccessToken,
label,
}: CreateTokenParams) => {
const { payload } = parseJWT(jwt);
return prisma.tokens.create({
Expand All @@ -18,6 +20,7 @@ export const createToken = async ({
walletAddress: payload.sub,
expiresAt: new Date(payload.exp * 1000),
isAccessToken,
label,
},
});
};
1 change: 1 addition & 0 deletions src/db/wallets/createWalletDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface CreateWalletDetailsParams {
pgtx?: PrismaTransaction;
address: string;
type: WalletType;
label?: string;
awsKmsKeyId?: string;
awsKmsArn?: string;
gcpKmsKeyRingId?: string;
Expand Down
Loading