Skip to content

Commit b22381e

Browse files
[Dashboard] Add error handling and refactor vault account rotation
1 parent ffb7b64 commit b22381e

File tree

4 files changed

+82
-53
lines changed

4 files changed

+82
-53
lines changed

apps/dashboard/src/@/components/project/create-project-modal/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ const CreateProjectDialog = (props: CreateProjectDialogProps) => {
6767
await createVaultAccountAndAccessToken({
6868
project: res.project,
6969
projectSecretKey: res.secret,
70+
}).catch((error) => {
71+
console.error(
72+
"Failed to create vault account and access token",
73+
error,
74+
);
75+
throw error;
7076
});
7177
return {
7278
project: res.project,

apps/dashboard/src/@/hooks/useApi.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
22
import { useActiveAccount } from "thirdweb/react";
33
import { apiServerProxy } from "@/actions/proxies";
44
import type { Project } from "@/api/projects";
5-
import { createVaultAccountAndAccessToken } from "../../app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client";
5+
import { rotateVaultAccountAndAccessToken } from "../../app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client";
66
import { accountKeys, authorizedWallets } from "../query-keys/cache-keys";
77

88
// FIXME: We keep repeating types, API server should provide them
@@ -331,12 +331,17 @@ export async function rotateSecretKeyClient(params: { project: Project }) {
331331
}
332332

333333
try {
334-
// if the project has a vault admin key, rotate it as well
335-
await createVaultAccountAndAccessToken({
336-
project: params.project,
337-
projectSecretKey: res.data.data.secret,
338-
projectSecretHash: res.data.data.secretHash,
339-
});
334+
// if the project has an encrypted vault admin key, rotate it as well
335+
const service = params.project.services.find(
336+
(service) => service.name === "engineCloud",
337+
);
338+
if (service?.encryptedAdminKey) {
339+
await rotateVaultAccountAndAccessToken({
340+
project: params.project,
341+
projectSecretKey: res.data.data.secret,
342+
projectSecretHash: res.data.data.secretHash,
343+
});
344+
}
340345
} catch (error) {
341346
console.error("Failed to rotate vault admin key", error);
342347
}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,51 @@ export async function initVaultClient() {
3030
return vc;
3131
}
3232

33+
export async function rotateVaultAccountAndAccessToken(props: {
34+
project: Project;
35+
projectSecretKey?: string;
36+
projectSecretHash?: string;
37+
}) {
38+
const vaultClient = await initVaultClient();
39+
const service = props.project.services.find(
40+
(service) => service.name === "engineCloud",
41+
);
42+
const storedRotationCode = service?.rotationCode;
43+
if (!storedRotationCode) {
44+
throw new Error("No rotation code found");
45+
}
46+
47+
const rotateServiceAccountRes = await rotateServiceAccount({
48+
client: vaultClient,
49+
request: {
50+
auth: {
51+
rotationCode: storedRotationCode,
52+
},
53+
},
54+
});
55+
if (rotateServiceAccountRes.error) {
56+
throw new Error(rotateServiceAccountRes.error.message);
57+
}
58+
const adminKey = rotateServiceAccountRes.data.newAdminKey;
59+
const rotationCode = rotateServiceAccountRes.data.newRotationCode;
60+
61+
const { managementToken, walletToken } =
62+
await createAndEncryptVaultAccessTokens({
63+
project: props.project,
64+
projectSecretKey: props.projectSecretKey,
65+
projectSecretHash: props.projectSecretHash,
66+
vaultClient,
67+
adminKey,
68+
rotationCode,
69+
});
70+
71+
return {
72+
adminKey,
73+
managementToken,
74+
walletToken,
75+
};
76+
}
77+
3378
export async function createVaultAccountAndAccessToken(props: {
3479
project: Project;
3580
projectSecretKey?: string;
@@ -38,53 +83,26 @@ export async function createVaultAccountAndAccessToken(props: {
3883
try {
3984
const vaultClient = await initVaultClient();
4085

41-
const service = props.project.services.find(
42-
(service) => service.name === "engineCloud",
43-
);
44-
const storedRotationCode = service?.rotationCode;
45-
const storedEncryptedAdminKey = service?.encryptedAdminKey;
46-
47-
let adminKey: string | null = null;
48-
let rotationCode: string | null = null;
49-
50-
if (storedRotationCode && storedEncryptedAdminKey) {
51-
// if the project has a managed vault admin key, rotate it
52-
const rotateServiceAccountRes = await rotateServiceAccount({
53-
client: vaultClient,
54-
request: {
55-
auth: {
56-
rotationCode: storedRotationCode,
86+
const serviceAccountResult = await createServiceAccount({
87+
client: vaultClient,
88+
request: {
89+
options: {
90+
metadata: {
91+
projectId: props.project.id,
92+
purpose: "Thirdweb Project Server Wallet Service Account",
93+
teamId: props.project.teamId,
5794
},
5895
},
59-
});
60-
if (rotateServiceAccountRes.error) {
61-
throw new Error(rotateServiceAccountRes.error.message);
62-
}
63-
adminKey = rotateServiceAccountRes.data.newAdminKey;
64-
rotationCode = rotateServiceAccountRes.data.newRotationCode;
65-
} else {
66-
// otherwise create a new service account
67-
const serviceAccountResult = await createServiceAccount({
68-
client: vaultClient,
69-
request: {
70-
options: {
71-
metadata: {
72-
projectId: props.project.id,
73-
purpose: "Thirdweb Project Server Wallet Service Account",
74-
teamId: props.project.teamId,
75-
},
76-
},
77-
},
78-
});
79-
if (serviceAccountResult.success === false) {
80-
throw new Error(
81-
`Failed to create service account: ${serviceAccountResult.error}`,
82-
);
83-
}
84-
const serviceAccount = serviceAccountResult.data;
85-
adminKey = serviceAccount.adminKey;
86-
rotationCode = serviceAccount.rotationCode;
96+
},
97+
});
98+
if (serviceAccountResult.success === false) {
99+
throw new Error(
100+
`Failed to create service account: ${serviceAccountResult.error}`,
101+
);
87102
}
103+
const serviceAccount = serviceAccountResult.data;
104+
const adminKey = serviceAccount.adminKey;
105+
const rotationCode = serviceAccount.rotationCode;
88106

89107
const { managementToken, walletToken } =
90108
await createAndEncryptVaultAccessTokens({

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/rotate-admin-key.client.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import { Spinner } from "@/components/ui/Spinner/Spinner";
2727
import { useDashboardRouter } from "@/lib/DashboardRouter";
2828
import { cn } from "@/lib/utils";
2929
import {
30-
createVaultAccountAndAccessToken,
3130
maskSecret,
31+
rotateVaultAccountAndAccessToken,
3232
} from "../../transactions/lib/vault.client";
3333

3434
export default function RotateAdminKeyButton(props: {
@@ -43,7 +43,7 @@ export default function RotateAdminKeyButton(props: {
4343
const rotateAdminKeyMutation = useMutation({
4444
mutationFn: async () => {
4545
// passing no secret key means we're rotating the admin key and deleting any stored keys
46-
const result = await createVaultAccountAndAccessToken({
46+
const result = await rotateVaultAccountAndAccessToken({
4747
project: props.project,
4848
});
4949

0 commit comments

Comments
 (0)