From b9d9be4f4698fc2cda7ce61fd732475e8cf0a629 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 12 Jan 2026 22:52:35 +0700 Subject: [PATCH] Add self-managed vault recovery option for lost secret key Introduces an option for users of managed vaults who have lost their secret key to create a new self-managed (ejected) vault. Updates the recovery dialog to allow users to choose between providing their secret key for a managed vault or proceeding with self-management, improving recovery flexibility and user experience. --- .../wallets/vault-recovery-card.client.tsx | 87 +++++++++++++------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/wallets/vault-recovery-card.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/wallets/vault-recovery-card.client.tsx index 4ecf93e63af..619992f67a3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/wallets/vault-recovery-card.client.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/wallets/vault-recovery-card.client.tsx @@ -45,6 +45,8 @@ export function VaultRecoveryCard({ const [dialogOpen, setDialogOpen] = useState(false); const [confirmed, setConfirmed] = useState(false); const [secretKeyInput, setSecretKeyInput] = useState(""); + // Option for managed vault users who lost their secret key + const [manageKeysSelf, setManageKeysSelf] = useState(false); // For ejected vault key download flow const [keysConfirmed, setKeysConfirmed] = useState(false); const [keysDownloaded, setKeysDownloaded] = useState(false); @@ -55,6 +57,9 @@ export function VaultRecoveryCard({ ); const wasManagedVault = !!engineCloudService?.encryptedAdminKey; + // Will create ejected vault if: wasn't managed, OR user chose to manage keys themselves + const willCreateEjectedVault = !wasManagedVault || manageKeysSelf; + const isInsufficientScopeError = errorMessage.includes("AUTH_INSUFFICIENT_SCOPE") || errorMessage.toLowerCase().includes("insufficient scope"); @@ -65,16 +70,16 @@ export function VaultRecoveryCard({ const result = await createVaultAccountAndAccessToken({ project, - // Only pass secret key if it was a managed vault and user provided one - projectSecretKey: wasManagedVault ? secretKeyInput : undefined, + // Only pass secret key if creating managed vault (not ejected) + projectSecretKey: willCreateEjectedVault ? undefined : secretKeyInput, }); return result; }, onSuccess: () => { - // For managed vaults, reload immediately (keys are encrypted with secret key) + // For managed vaults (with secret key), reload immediately // For ejected vaults, show the key download dialog first - if (wasManagedVault) { + if (!willCreateEjectedVault) { window.location.reload(); } // For ejected vaults, we stay in the dialog to show the admin key @@ -110,10 +115,11 @@ export function VaultRecoveryCard({ window.location.reload(); }; - // For managed vaults, require secret key input - const canProceed = wasManagedVault - ? confirmed && secretKeyInput.trim().length > 0 - : confirmed; + // For managed vaults creating managed vault, require secret key input + // For ejected vaults (or managed choosing to manage keys), just need confirmation + const canProceed = willCreateEjectedVault + ? confirmed + : confirmed && secretKeyInput.trim().length > 0; if (!isInsufficientScopeError) { // Show standard error for non-scope errors @@ -164,7 +170,7 @@ export function VaultRecoveryCard({ {/* Show key download UI for ejected vaults after success */} - {!wasManagedVault && regenerateMutation.data ? ( + {willCreateEjectedVault && regenerateMutation.data ? ( <> Save your Vault Admin Key @@ -267,24 +273,50 @@ export function VaultRecoveryCard({ {wasManagedVault && ( -
- - setSecretKeyInput(e.target.value)} - /> -

- Your secret key is required to create a managed - vault. -

+
+ {!manageKeysSelf && ( + <> + + + setSecretKeyInput(e.target.value) + } + /> +

+ Your secret key is required to create a managed + vault. +

+ + )} + +
+ { + setManageKeysSelf(checked === true); + if (checked) { + setSecretKeyInput(""); + } + }} + /> + +
)} @@ -312,6 +344,7 @@ export function VaultRecoveryCard({ onClick={() => { setConfirmed(false); setSecretKeyInput(""); + setManageKeysSelf(false); }} > Cancel