diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index e3136fae3..5b185b97a 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -34,7 +34,8 @@ export const workspaceKeys = { getUserWsEnvironments: (workspaceId: string) => ["workspace-env", { workspaceId }] as const, getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const, getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }] as const, - getWorkspaceServiceTokenDataV3: (workspaceId: string) => [{ workspaceId }, "workspace-service-token-data-v3"] as const + getWorkspaceServiceTokenDataV3: (workspaceId: string) => + [{ workspaceId }, "workspace-service-token-data-v3"] as const }; const fetchWorkspaceById = async (workspaceId: string) => { @@ -53,7 +54,7 @@ const fetchWorkspaceIndexStatus = async (workspaceId: string) => { return data; }; -const fetchWorkspaceSecrets = async (workspaceId: string) => { +export const fetchWorkspaceSecrets = async (workspaceId: string) => { const { data: { secrets } } = await apiRequest.get<{ secrets: EncryptedSecret[] }>( @@ -253,9 +254,18 @@ export const useReorderWsEnvironment = () => { const queryClient = useQueryClient(); return useMutation<{}, {}, ReorderEnvironmentsDTO>({ - mutationFn: ({ workspaceID, environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName}) => { + mutationFn: ({ + workspaceID, + environmentSlug, + environmentName, + otherEnvironmentSlug, + otherEnvironmentName + }) => { return apiRequest.patch(`/api/v2/workspace/${workspaceID}/environments`, { - environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName + environmentSlug, + environmentName, + otherEnvironmentSlug, + otherEnvironmentName }); }, onSuccess: () => { @@ -378,4 +388,4 @@ export const useGetWorkspaceServiceTokenDataV3 = (workspaceId: string) => { }, enabled: true }); -}; \ No newline at end of file +}; diff --git a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx index 7667eaeb6..0cb590631 100644 --- a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx +++ b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx @@ -41,6 +41,7 @@ import { } from "@app/hooks/api"; import { FolderBreadCrumbs } from "./components/FolderBreadCrumbs"; +import { ProjectIndexSecretsSection } from "./components/ProjectIndexSecretsSection"; import { SecretOverviewFolderRow } from "./components/SecretOverviewFolderRow"; import { SecretOverviewTableRow } from "./components/SecretOverviewTableRow"; @@ -259,6 +260,7 @@ export const SecretOverviewPage = () => { return (
+
diff --git a/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx b/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx new file mode 100644 index 000000000..23cfa750d --- /dev/null +++ b/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx @@ -0,0 +1,98 @@ +import { ProjectPermissionCan } from "@app/components/permissions"; +import { + decryptAssymmetric, + decryptSymmetric +} from "@app/components/utilities/cryptography/crypto"; +import { Button, Spinner } from "@app/components/v2"; +import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { useToggle } from "@app/hooks"; +import { useGetWorkspaceIndexStatus, useNameWorkspaceSecrets } from "@app/hooks/api"; +import { UserWsKeyPair } from "@app/hooks/api/types"; +import { fetchWorkspaceSecrets } from "@app/hooks/api/workspace/queries"; + +// TODO: add check so that this only shows up if user is +// an admin in the workspace +type Props = { + decryptFileKey: UserWsKeyPair; +}; + +export const ProjectIndexSecretsSection = ({ decryptFileKey }: Props) => { + const { currentWorkspace } = useWorkspace(); + const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } = useGetWorkspaceIndexStatus( + currentWorkspace?._id ?? "" + ); + const [isIndexing, setIsIndexing] = useToggle(); + const nameWorkspaceSecrets = useNameWorkspaceSecrets(); + + const onEnableBlindIndices = async () => { + if (!currentWorkspace?._id) return; + setIsIndexing.on(); + try { + const encryptedSecrets = await fetchWorkspaceSecrets(currentWorkspace._id); + + const key = decryptAssymmetric({ + ciphertext: decryptFileKey.encryptedKey, + nonce: decryptFileKey.nonce, + publicKey: decryptFileKey.sender.publicKey, + privateKey: localStorage.getItem("PRIVATE_KEY") as string + }); + + const secretsToUpdate = encryptedSecrets.map((encryptedSecret) => { + const secretName = decryptSymmetric({ + ciphertext: encryptedSecret.secretKeyCiphertext, + iv: encryptedSecret.secretKeyIV, + tag: encryptedSecret.secretKeyTag, + key + }); + + return { + secretName, + _id: encryptedSecret._id + }; + }); + await nameWorkspaceSecrets.mutateAsync({ + workspaceId: currentWorkspace._id, + secretsToUpdate + }); + } catch (err) { + console.log(err); + } finally { + setIsIndexing.off(); + } + }; + + return !isBlindIndexedLoading && !isBlindIndexed ? ( +
+ {isIndexing && ( +
+ +
+
Please wait
+ Re-indexing your secrets... +
+
+ )} +

Enable Blind Indices

+

+ Your project was created before the introduction of blind indexing. + To continue accessing secrets by name through the SDK, public API and web dashboard, please enable blind + indexing. This is a one time process. +

+ + {(isAllowed) => ( + + )} + +
+ ) : ( +
+ ); +}; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectIndexSecretsSection/index.tsx b/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/index.tsx similarity index 100% rename from frontend/src/views/Settings/ProjectSettingsPage/components/ProjectIndexSecretsSection/index.tsx rename to frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/index.tsx diff --git a/frontend/src/views/SecretRotationPage/components/CreateRotationForm/CreateRotationForm.tsx b/frontend/src/views/SecretRotationPage/components/CreateRotationForm/CreateRotationForm.tsx index 3576cc0f9..5d4ed8073 100644 --- a/frontend/src/views/SecretRotationPage/components/CreateRotationForm/CreateRotationForm.tsx +++ b/frontend/src/views/SecretRotationPage/components/CreateRotationForm/CreateRotationForm.tsx @@ -1,12 +1,11 @@ import { useRef, useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; +import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { Modal, ModalContent, Step, Stepper } from "@app/components/v2"; import { useCreateSecretRotation } from "@app/hooks/api"; import { TSecretRotationProvider } from "@app/hooks/api/types"; -import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider"; - import { RotationInputForm } from "./steps/RotationInputForm"; import { RotationOutputForm, diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectGeneralTab/ProjectGeneralTab.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectGeneralTab/ProjectGeneralTab.tsx index cacfda8bb..bbd8e78d4 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectGeneralTab/ProjectGeneralTab.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectGeneralTab/ProjectGeneralTab.tsx @@ -2,20 +2,18 @@ import { AutoCapitalizationSection } from "../AutoCapitalizationSection"; import { DeleteProjectSection } from "../DeleteProjectSection"; import { E2EESection } from "../E2EESection"; import { EnvironmentSection } from "../EnvironmentSection"; -import { ProjectIndexSecretsSection } from "../ProjectIndexSecretsSection"; import { ProjectNameChangeSection } from "../ProjectNameChangeSection"; import { SecretTagsSection } from "../SecretTagsSection"; export const ProjectGeneralTab = () => { - return ( -
- - - - - - - -
- ); -} \ No newline at end of file + return ( +
+ + + + + + +
+ ); +}; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx deleted file mode 100644 index ca2e14eb9..000000000 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { ProjectPermissionCan } from "@app/components/permissions"; -import { - decryptAssymmetric, - decryptSymmetric -} from "@app/components/utilities/cryptography/crypto"; -import { Button } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; -import { - useGetUserWsKey, - useGetWorkspaceIndexStatus, - useGetWorkspaceSecrets, - useNameWorkspaceSecrets -} from "@app/hooks/api"; - -// TODO: add check so that this only shows up if user is -// an admin in the workspace - -export const ProjectIndexSecretsSection = () => { - const { currentWorkspace } = useWorkspace(); - const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } = useGetWorkspaceIndexStatus( - currentWorkspace?._id ?? "" - ); - const { data: latestFileKey } = useGetUserWsKey(currentWorkspace?._id ?? ""); - const { data: encryptedSecrets } = useGetWorkspaceSecrets(currentWorkspace?._id ?? ""); - const nameWorkspaceSecrets = useNameWorkspaceSecrets(); - - const onEnableBlindIndices = async () => { - if (!currentWorkspace?._id) return; - if (!encryptedSecrets) return; - if (!latestFileKey) return; - - const key = decryptAssymmetric({ - ciphertext: latestFileKey.encryptedKey, - nonce: latestFileKey.nonce, - publicKey: latestFileKey.sender.publicKey, - privateKey: localStorage.getItem("PRIVATE_KEY") as string - }); - - const secretsToUpdate = encryptedSecrets.map((encryptedSecret) => { - const secretName = decryptSymmetric({ - ciphertext: encryptedSecret.secretKeyCiphertext, - iv: encryptedSecret.secretKeyIV, - tag: encryptedSecret.secretKeyTag, - key - }); - - return { - secretName, - _id: encryptedSecret._id - }; - }); - - await nameWorkspaceSecrets.mutateAsync({ - workspaceId: currentWorkspace._id, - secretsToUpdate - }); - }; - - return !isBlindIndexedLoading && !isBlindIndexed ? ( -
-

Blind Indices

-

- Your project, created before the introduction of blind indexing, contains unindexed secrets. - To access individual secrets by name through the SDK and public API, please enable blind - indexing. -

- - {(isAllowed) => ( - - )} - -
- ) : ( -
- ); -}; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx index 5f9e1013b..757dfc6b2 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx @@ -2,7 +2,6 @@ export { AutoCapitalizationSection } from "./AutoCapitalizationSection"; export { DeleteProjectSection } from "./DeleteProjectSection"; export { E2EESection } from "./E2EESection"; export { EnvironmentSection } from "./EnvironmentSection"; -export { ProjectIndexSecretsSection } from "./ProjectIndexSecretsSection"; export { ProjectNameChangeSection } from "./ProjectNameChangeSection"; export { SecretTagsSection } from "./SecretTagsSection"; export { ServiceTokenSection } from "./ServiceTokenSection"; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index d5a16121a..42ea0e773 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -2,15 +2,16 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "~/components/*": ["./src/components/*"], - "~/hooks/*": ["./src/hooks/*"], - "~/utilities/*": ["./src/components/utilities/*"], - "~/*": ["./src/const"], - "~/pages/*": ["./src/pages/*"], - "@app/*": ["./src/*"] + "@app/*": [ + "./src/*" + ] }, "target": "ESNext", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -25,6 +26,14 @@ "jsx": "preserve", "incremental": true }, - "include": ["next-i18next.config.js", "next-env.d.ts", "./src/**/*.ts", "./src/**/*.tsx", "./.eslintrc.js"], - "exclude": ["node_modules"] + "include": [ + "next-i18next.config.js", + "next-env.d.ts", + "./src/**/*.ts", + "./src/**/*.tsx", + "./.eslintrc.js" + ], + "exclude": [ + "node_modules" + ] }