mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 23:52:09 +00:00
Add frontend migration support for existing project to be blind-indexed
This commit is contained in:
@@ -9,8 +9,8 @@ import NavHeader from '@app/components/navigation/NavHeader';
|
||||
// TODO(akhilmhdh):Refactor this into a better utility module package
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
encryptSymmetric
|
||||
} from '@app/components/utilities/cryptography/crypto';
|
||||
decryptSymmetric,
|
||||
encryptSymmetric} from '@app/components/utilities/cryptography/crypto';
|
||||
import { Button, FormControl, Input } from '@app/components/v2';
|
||||
import { plans } from '@app/const';
|
||||
import { useSubscription, useWorkspace } from '@app/context';
|
||||
@@ -25,11 +25,13 @@ import {
|
||||
useDeleteWsTag,
|
||||
useGetUserWsKey,
|
||||
useGetUserWsServiceTokens,
|
||||
useGetWorkspaceIndexStatus,
|
||||
useGetWorkspaceSecrets,
|
||||
useGetWsTags,
|
||||
useNameWorkspaceSecrets,
|
||||
useRenameWorkspace,
|
||||
useToggleAutoCapitalization,
|
||||
useUpdateWsEnvironment
|
||||
} from '@app/hooks/api';
|
||||
useUpdateWsEnvironment} from '@app/hooks/api';
|
||||
|
||||
import { AutoCapitalizationSection } from './components/AutoCapitalizationSection/AutoCapitalizationSection';
|
||||
import { SecretTagsSection } from './components/SecretTagsSection';
|
||||
@@ -39,9 +41,10 @@ import {
|
||||
CreateUpdateEnvFormData,
|
||||
CreateWsTag,
|
||||
EnvironmentSection,
|
||||
ProjectEncryptionModeSection,
|
||||
ProjectIndexSecretsSection,
|
||||
ProjectNameChangeSection,
|
||||
ServiceTokenSection} from './components';
|
||||
ServiceTokenSection
|
||||
} from './components';
|
||||
|
||||
export const ProjectSettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -55,6 +58,7 @@ export const ProjectSettingsPage = () => {
|
||||
const [isDeleting, setIsDeleting] = useToggle();
|
||||
|
||||
const renameWorkspace = useRenameWorkspace();
|
||||
const nameWorkspaceSecrets = useNameWorkspaceSecrets();
|
||||
const toggleAutoCapitalization = useToggleAutoCapitalization();
|
||||
|
||||
const deleteWorkspace = useDeleteWorkspace();
|
||||
@@ -63,11 +67,16 @@ export const ProjectSettingsPage = () => {
|
||||
const updateWsEnv = useUpdateWsEnvironment();
|
||||
const deleteWsEnv = useDeleteWsEnvironment();
|
||||
|
||||
const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } = useGetWorkspaceIndexStatus(workspaceID);
|
||||
|
||||
// service token
|
||||
const { data: serviceTokens, isLoading: isServiceTokenLoading } = useGetUserWsServiceTokens({
|
||||
workspaceID: currentWorkspace?._id || ''
|
||||
});
|
||||
|
||||
const { data: latestFileKey } = useGetUserWsKey(workspaceID);
|
||||
const { data: encryptedSecrets } = useGetWorkspaceSecrets(workspaceID);
|
||||
|
||||
const createServiceToken = useCreateServiceToken();
|
||||
const deleteServiceToken = useDeleteServiceToken();
|
||||
|
||||
@@ -207,14 +216,15 @@ export const ProjectSettingsPage = () => {
|
||||
// type guard
|
||||
if (!latestFileKey) return '';
|
||||
try {
|
||||
// crypo calculation to generate the key
|
||||
const key = decryptAssymmetric({
|
||||
ciphertext: latestFileKey.encryptedKey,
|
||||
nonce: latestFileKey.nonce,
|
||||
publicKey: latestFileKey.sender.publicKey,
|
||||
privateKey: localStorage.getItem('PRIVATE_KEY') as string
|
||||
});
|
||||
|
||||
const randomBytes = crypto.randomBytes(16).toString('hex');
|
||||
|
||||
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||
plaintext: key,
|
||||
key: randomBytes
|
||||
@@ -303,6 +313,38 @@ export const ProjectSettingsPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
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 (
|
||||
<div className="dark container mx-auto flex flex-col px-8 text-mineshaft-50 dark:[color-scheme:dark]">
|
||||
{/* TODO(akhilmhdh): Remove this right when layout is refactored */}
|
||||
@@ -349,7 +391,11 @@ export const ProjectSettingsPage = () => {
|
||||
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
|
||||
onAutoCapitalizationChange={onAutoCapitalizationToggle}
|
||||
/>
|
||||
<ProjectEncryptionModeSection />
|
||||
{!isBlindIndexedLoading && !isBlindIndexed && (
|
||||
<ProjectIndexSecretsSection
|
||||
onEnableBlindIndices={onEnableBlindIndices}
|
||||
/>
|
||||
)}
|
||||
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4">
|
||||
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
|
||||
<p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p>
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import {
|
||||
Controller,
|
||||
useForm
|
||||
} from 'react-hook-form';
|
||||
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import * as yup from 'yup';
|
||||
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '@app/components/v2';
|
||||
|
||||
// TODO: modify in accordance with what was discussed with
|
||||
// Maidul
|
||||
|
||||
// Do with select for now them replace.
|
||||
|
||||
const items = [
|
||||
{ value: 'e2ee', label: 'E2EE' },
|
||||
{ value: 'blind-indexed-e2ee', label: 'Blind Indexed E2EE' }
|
||||
];
|
||||
|
||||
const formSchema = yup.object({
|
||||
mode: yup.string().required().label('Project Mode')
|
||||
});
|
||||
|
||||
type FormData = yup.InferType<typeof formSchema>;
|
||||
|
||||
export const ProjectEncryptionModeSection = () => {
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
reset,
|
||||
formState: { isDirty, isSubmitting }
|
||||
} = useForm<FormData>({ resolver: yupResolver(formSchema) });
|
||||
|
||||
useEffect(() => {
|
||||
reset({ mode: 'blind-indexed-e2ee' });
|
||||
}, []);
|
||||
|
||||
const onFormSubmit = async ({ mode }: FormData) => {
|
||||
console.log('onFormSubmit');
|
||||
console.log('mode: ', mode);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="rounded-md bg-white/5 p-6"
|
||||
>
|
||||
<p className="mb-4 text-xl font-semibold">Encryption Mode</p>
|
||||
<div className="mb-6 max-w-lg">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
console.log('field: ', field);
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Select
|
||||
{...field}
|
||||
className="w-full"
|
||||
>
|
||||
{items.map(item => (
|
||||
<SelectItem value={item.value} key={`enc-mode-${item.value}`}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
control={control}
|
||||
name="mode"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
isLoading={isSubmitting}
|
||||
color="mineshaft"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isDisabled={!isDirty || isSubmitting}
|
||||
leftIcon={<FontAwesomeIcon icon={faCheck} />}
|
||||
>
|
||||
Save Changes
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import { Button } from '@app/components/v2';
|
||||
|
||||
// TODO: add check so that this only shows up if user is
|
||||
// an admin in the workspace
|
||||
|
||||
type Props = {
|
||||
onEnableBlindIndices: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const ProjectIndexSecretsSection = ({
|
||||
onEnableBlindIndices
|
||||
}: Props) => {
|
||||
return (
|
||||
<div className="rounded-md bg-white/5 p-6">
|
||||
<p className="mb-4 text-xl font-semibold">Blind Indices</p>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
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>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Learn more about it here.
|
||||
</p>
|
||||
<Button
|
||||
onClick={onEnableBlindIndices}
|
||||
color="mineshaft"
|
||||
size="sm"
|
||||
type="submit"
|
||||
>
|
||||
Enable Blind Indexing
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { ProjectIndexSecretsSection } from './ProjectIndexSecretsSection';
|
||||
@@ -1,7 +1,7 @@
|
||||
export { CopyProjectIDSection } from './CopyProjectIDSection';
|
||||
export { EnvironmentSection } from './EnvironmentSection';
|
||||
export type { CreateUpdateEnvFormData } from './EnvironmentSection/EnvironmentSection';
|
||||
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';
|
||||
export { ProjectIndexSecretsSection } from './ProjectIndexSecretsSection';
|
||||
export { ProjectNameChangeSection } from './ProjectNameChangeSection';
|
||||
export type { CreateWsTag } from './SecretTagsSection/SecretTagsSection';
|
||||
export { ServiceTokenSection } from './ServiceTokenSection';
|
||||
|
||||
Reference in New Issue
Block a user