diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/EncryptionTab/EncryptionTab.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/EncryptionTab/EncryptionTab.tsx
index 7c8724bad..553e89218 100644
--- a/frontend/src/views/Settings/ProjectSettingsPage/components/EncryptionTab/EncryptionTab.tsx
+++ b/frontend/src/views/Settings/ProjectSettingsPage/components/EncryptionTab/EncryptionTab.tsx
@@ -1,20 +1,32 @@
-import { useEffect, useState } from "react";
+import { ChangeEvent, useEffect, useRef, useState } from "react";
import { Controller, useForm } from "react-hook-form";
+import { faUpload } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import FileSaver from "file-saver";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
-import { Button, FormControl, Select, SelectItem } from "@app/components/v2";
+import {
+ Button,
+ FormControl,
+ IconButton,
+ Modal,
+ ModalContent,
+ Select,
+ SelectItem
+} from "@app/components/v2";
import {
ProjectPermissionActions,
ProjectPermissionSub,
useOrganization,
useWorkspace
} from "@app/context";
+import { usePopUp } from "@app/hooks";
import { useGetActiveProjectKms, useGetExternalKmsList, useUpdateProjectKms } from "@app/hooks/api";
import { fetchProjectKmsBackup } from "@app/hooks/api/kms/queries";
+import { Organization, Workspace } from "@app/hooks/api/types";
const formSchema = z.object({
kmsKeyId: z.string()
@@ -24,6 +36,155 @@ type TForm = z.infer;
const INTERNAL_KMS_KEY_ID = "internal";
+const BackupConfirmationModal = ({
+ isOpen,
+ onOpenChange,
+ org,
+ workspace
+}: {
+ isOpen: boolean;
+ onOpenChange: (state: boolean) => void;
+ org?: Organization;
+ workspace?: Workspace;
+}) => {
+ const downloadKmsBackup = async () => {
+ if (!workspace || !org) {
+ return;
+ }
+
+ const { secretManager } = await fetchProjectKmsBackup(workspace.id);
+
+ const [, , kmsFunction] = secretManager.split(".");
+ const file = secretManager;
+
+ const blob = new Blob([file], { type: "text/plain;charset=utf-8" });
+ FileSaver.saveAs(blob, `kms-backup-${org.slug}-${workspace.slug}-${kmsFunction}.infisical.txt`);
+ };
+
+ return (
+
+
+
+ In case of interruptions with your configured external KMS, use this generated backup to
+ set the project's KMS back to the default Infisical KMS.
+
+
+ Note: The project data key will be encrypted the organization's default Infisical
+ KMS.
+
+ Continue
+ onOpenChange(false)}
+ colorSchema="secondary"
+ variant="plain"
+ className="ml-4"
+ >
+ Cancel
+
+
+
+ );
+};
+
+const LoadBackupModal = ({
+ isOpen,
+ onOpenChange,
+ org,
+ workspace
+}: {
+ isOpen: boolean;
+ onOpenChange: (state: boolean) => void;
+ org?: Organization;
+ workspace?: Workspace;
+}) => {
+ const fileUploadRef = useRef(null);
+ const [backupContent, setBackupContent] = useState("");
+ const [backupFileName, setBackupFileName] = useState("");
+
+ const uploadKmsBackup = async () => {
+ if (!workspace || !org) {
+ // eslint-disable-next-line no-useless-return
+ return;
+ }
+ };
+
+ const parseFile = (file?: File) => {
+ if (!file) {
+ createNotification({
+ text: "Failed to parse uploaded file.",
+ type: "error"
+ });
+ return;
+ }
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ if (!event?.target?.result) return;
+ const data = event.target.result.toString();
+ setBackupContent(data);
+ };
+
+ try {
+ reader.readAsText(file);
+ } catch (error) {
+ console.log(error);
+ }
+ };
+
+ const handleFileUpload = (e: ChangeEvent) => {
+ e.preventDefault();
+ parseFile(e.target?.files?.[0]);
+ setBackupFileName(e.target?.files?.[0]?.name || "");
+ };
+
+ return (
+ {
+ setBackupContent("");
+ setBackupFileName("");
+ onOpenChange(state);
+ }}
+ >
+
+
+ By loading a backup, the project's KMS will be switched to the default Infisical KMS.
+
+
+ If left unmodified, the filename of the backup should look like the following:
+
{`kms-backup-${org?.slug}-${workspace?.slug}-secretManager.infisical.txt`}
+
+
+
+ {
+ fileUploadRef?.current?.click();
+ }}
+ >
+
+
+
+ {backupFileName && {backupFileName}
}
+ {backupContent && (
+
+ Continue
+
+ )}
+
+
+ );
+};
+
export const EncryptionTab = () => {
const { currentOrg } = useOrganization();
const { currentWorkspace } = useWorkspace();
@@ -32,6 +193,10 @@ export const EncryptionTab = () => {
const { data: activeKms } = useGetActiveProjectKms(currentWorkspace?.id!);
const { mutateAsync: updateProjectKms } = useUpdateProjectKms(currentWorkspace?.id!);
+ const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp([
+ "createBackupConfirmation",
+ "loadBackup"
+ ] as const);
const [kmsKeyId, setKmsKeyId] = useState("");
const {
@@ -72,23 +237,6 @@ export const EncryptionTab = () => {
}
};
- const downloadKmsBackup = async () => {
- if (!currentWorkspace || !currentOrg) {
- return;
- }
-
- const { secretManager } = await fetchProjectKmsBackup(currentWorkspace.id);
-
- const [, , kmsFunction] = secretManager.split(".");
- const file = secretManager;
-
- const blob = new Blob([file], { type: "text/plain;charset=utf-8" });
- FileSaver.saveAs(
- blob,
- `kms-backup-${currentOrg.slug}-${currentWorkspace.slug}-${kmsFunction}.infisical.txt`
- );
- };
-
return (
);
};