mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 19:26:19 +00:00
Merge pull request #1153 from akhilmhdh/feat/secret-blind-index-overview
feat: changed enable blindIndex from settings to overview page for attention
This commit is contained in:
@@ -34,7 +34,8 @@ export const workspaceKeys = {
|
|||||||
getUserWsEnvironments: (workspaceId: string) => ["workspace-env", { workspaceId }] as const,
|
getUserWsEnvironments: (workspaceId: string) => ["workspace-env", { workspaceId }] as const,
|
||||||
getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const,
|
getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const,
|
||||||
getWorkspaceUsers: (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) => {
|
const fetchWorkspaceById = async (workspaceId: string) => {
|
||||||
@@ -53,7 +54,7 @@ const fetchWorkspaceIndexStatus = async (workspaceId: string) => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchWorkspaceSecrets = async (workspaceId: string) => {
|
export const fetchWorkspaceSecrets = async (workspaceId: string) => {
|
||||||
const {
|
const {
|
||||||
data: { secrets }
|
data: { secrets }
|
||||||
} = await apiRequest.get<{ secrets: EncryptedSecret[] }>(
|
} = await apiRequest.get<{ secrets: EncryptedSecret[] }>(
|
||||||
@@ -253,9 +254,18 @@ export const useReorderWsEnvironment = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation<{}, {}, ReorderEnvironmentsDTO>({
|
return useMutation<{}, {}, ReorderEnvironmentsDTO>({
|
||||||
mutationFn: ({ workspaceID, environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName}) => {
|
mutationFn: ({
|
||||||
|
workspaceID,
|
||||||
|
environmentSlug,
|
||||||
|
environmentName,
|
||||||
|
otherEnvironmentSlug,
|
||||||
|
otherEnvironmentName
|
||||||
|
}) => {
|
||||||
return apiRequest.patch(`/api/v2/workspace/${workspaceID}/environments`, {
|
return apiRequest.patch(`/api/v2/workspace/${workspaceID}/environments`, {
|
||||||
environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName
|
environmentSlug,
|
||||||
|
environmentName,
|
||||||
|
otherEnvironmentSlug,
|
||||||
|
otherEnvironmentName
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -378,4 +388,4 @@ export const useGetWorkspaceServiceTokenDataV3 = (workspaceId: string) => {
|
|||||||
},
|
},
|
||||||
enabled: true
|
enabled: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
|
|
||||||
import { FolderBreadCrumbs } from "./components/FolderBreadCrumbs";
|
import { FolderBreadCrumbs } from "./components/FolderBreadCrumbs";
|
||||||
|
import { ProjectIndexSecretsSection } from "./components/ProjectIndexSecretsSection";
|
||||||
import { SecretOverviewFolderRow } from "./components/SecretOverviewFolderRow";
|
import { SecretOverviewFolderRow } from "./components/SecretOverviewFolderRow";
|
||||||
import { SecretOverviewTableRow } from "./components/SecretOverviewTableRow";
|
import { SecretOverviewTableRow } from "./components/SecretOverviewTableRow";
|
||||||
|
|
||||||
@@ -259,6 +260,7 @@ export const SecretOverviewPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
<div className="container mx-auto px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
||||||
|
<ProjectIndexSecretsSection decryptFileKey={latestFileKey!} />
|
||||||
<div className="relative right-5 ml-4">
|
<div className="relative right-5 ml-4">
|
||||||
<NavHeader pageName={t("dashboard.title")} isProjectRelated />
|
<NavHeader pageName={t("dashboard.title")} isProjectRelated />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+98
@@ -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 ? (
|
||||||
|
<div className="p-4 mt-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
|
||||||
|
{isIndexing && (
|
||||||
|
<div className="w-screen absolute top-0 left-0 h-screen z-50 bg-bunker-500 bg-opacity-80 flex items-center justify-center">
|
||||||
|
<Spinner size="lg" className="text-primary" />
|
||||||
|
<div className="flex flex-col space-y-1 ml-4">
|
||||||
|
<div className="text-3xl font-medium">Please wait</div>
|
||||||
|
<span className="inline-block">Re-indexing your secrets...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<p className="mb-2 text-lg font-semibold">Enable Blind Indices</p>
|
||||||
|
<p className="text-gray-400 mb-4 leading-7">
|
||||||
|
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. <b>This is a one time process.</b>
|
||||||
|
</p>
|
||||||
|
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
||||||
|
{(isAllowed) => (
|
||||||
|
<Button
|
||||||
|
onClick={onEnableBlindIndices}
|
||||||
|
isDisabled={!isAllowed}
|
||||||
|
color="mineshaft"
|
||||||
|
type="submit"
|
||||||
|
isLoading={isIndexing}
|
||||||
|
>
|
||||||
|
Enable Blind Indexing
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</ProjectPermissionCan>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
-2
@@ -1,12 +1,11 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { AnimatePresence, motion } from "framer-motion";
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
|
||||||
|
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||||
import { Modal, ModalContent, Step, Stepper } from "@app/components/v2";
|
import { Modal, ModalContent, Step, Stepper } from "@app/components/v2";
|
||||||
import { useCreateSecretRotation } from "@app/hooks/api";
|
import { useCreateSecretRotation } from "@app/hooks/api";
|
||||||
import { TSecretRotationProvider } from "@app/hooks/api/types";
|
import { TSecretRotationProvider } from "@app/hooks/api/types";
|
||||||
|
|
||||||
import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider";
|
|
||||||
|
|
||||||
import { RotationInputForm } from "./steps/RotationInputForm";
|
import { RotationInputForm } from "./steps/RotationInputForm";
|
||||||
import {
|
import {
|
||||||
RotationOutputForm,
|
RotationOutputForm,
|
||||||
|
|||||||
+11
-13
@@ -2,20 +2,18 @@ import { AutoCapitalizationSection } from "../AutoCapitalizationSection";
|
|||||||
import { DeleteProjectSection } from "../DeleteProjectSection";
|
import { DeleteProjectSection } from "../DeleteProjectSection";
|
||||||
import { E2EESection } from "../E2EESection";
|
import { E2EESection } from "../E2EESection";
|
||||||
import { EnvironmentSection } from "../EnvironmentSection";
|
import { EnvironmentSection } from "../EnvironmentSection";
|
||||||
import { ProjectIndexSecretsSection } from "../ProjectIndexSecretsSection";
|
|
||||||
import { ProjectNameChangeSection } from "../ProjectNameChangeSection";
|
import { ProjectNameChangeSection } from "../ProjectNameChangeSection";
|
||||||
import { SecretTagsSection } from "../SecretTagsSection";
|
import { SecretTagsSection } from "../SecretTagsSection";
|
||||||
|
|
||||||
export const ProjectGeneralTab = () => {
|
export const ProjectGeneralTab = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ProjectNameChangeSection />
|
<ProjectNameChangeSection />
|
||||||
<EnvironmentSection />
|
<EnvironmentSection />
|
||||||
<SecretTagsSection />
|
<SecretTagsSection />
|
||||||
<AutoCapitalizationSection />
|
<AutoCapitalizationSection />
|
||||||
<ProjectIndexSecretsSection />
|
<E2EESection />
|
||||||
<E2EESection />
|
<DeleteProjectSection />
|
||||||
<DeleteProjectSection />
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
}
|
|
||||||
|
|||||||
-84
@@ -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 ? (
|
|
||||||
<div className="mb-6 p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
|
|
||||||
<p className="mb-3 text-xl font-semibold">Blind Indices</p>
|
|
||||||
<p className="text-gray-400 mb-8">
|
|
||||||
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.
|
|
||||||
</p>
|
|
||||||
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
|
||||||
{(isAllowed) => (
|
|
||||||
<Button
|
|
||||||
onClick={onEnableBlindIndices}
|
|
||||||
isDisabled={!isAllowed}
|
|
||||||
color="mineshaft"
|
|
||||||
size="sm"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Enable Blind Indexing
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</ProjectPermissionCan>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div />
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,6 @@ export { AutoCapitalizationSection } from "./AutoCapitalizationSection";
|
|||||||
export { DeleteProjectSection } from "./DeleteProjectSection";
|
export { DeleteProjectSection } from "./DeleteProjectSection";
|
||||||
export { E2EESection } from "./E2EESection";
|
export { E2EESection } from "./E2EESection";
|
||||||
export { EnvironmentSection } from "./EnvironmentSection";
|
export { EnvironmentSection } from "./EnvironmentSection";
|
||||||
export { ProjectIndexSecretsSection } from "./ProjectIndexSecretsSection";
|
|
||||||
export { ProjectNameChangeSection } from "./ProjectNameChangeSection";
|
export { ProjectNameChangeSection } from "./ProjectNameChangeSection";
|
||||||
export { SecretTagsSection } from "./SecretTagsSection";
|
export { SecretTagsSection } from "./SecretTagsSection";
|
||||||
export { ServiceTokenSection } from "./ServiceTokenSection";
|
export { ServiceTokenSection } from "./ServiceTokenSection";
|
||||||
|
|||||||
+18
-9
@@ -2,15 +2,16 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"~/components/*": ["./src/components/*"],
|
"@app/*": [
|
||||||
"~/hooks/*": ["./src/hooks/*"],
|
"./src/*"
|
||||||
"~/utilities/*": ["./src/components/utilities/*"],
|
]
|
||||||
"~/*": ["./src/const"],
|
|
||||||
"~/pages/*": ["./src/pages/*"],
|
|
||||||
"@app/*": ["./src/*"]
|
|
||||||
},
|
},
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -25,6 +26,14 @@
|
|||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": ["next-i18next.config.js", "next-env.d.ts", "./src/**/*.ts", "./src/**/*.tsx", "./.eslintrc.js"],
|
"include": [
|
||||||
"exclude": ["node_modules"]
|
"next-i18next.config.js",
|
||||||
|
"next-env.d.ts",
|
||||||
|
"./src/**/*.ts",
|
||||||
|
"./src/**/*.tsx",
|
||||||
|
"./.eslintrc.js"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user