mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 11:29:42 +00:00
Ghost user and migration finished!
This commit is contained in:
@@ -56,7 +56,6 @@ const encryptSecrets = async ({
|
||||
publicKey: wsKey.sender.publicKey,
|
||||
privateKey: PRIVATE_KEY
|
||||
});
|
||||
|
||||
} else {
|
||||
// case: a (shared) key does not exist for the workspace
|
||||
randomBytes = crypto.randomBytes(16).toString("hex");
|
||||
@@ -116,7 +115,6 @@ const encryptSecrets = async ({
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error while encrypting secrets");
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ const encKeyKeys = {
|
||||
getUserWorkspaceKey: (workspaceID: string) => ["workspace-key-pair", { workspaceID }] as const
|
||||
};
|
||||
|
||||
export const fetchUserWsKey = async (workspaceID: string) => {
|
||||
export const fetchUserWsKey = async (projectId: string) => {
|
||||
const { data } = await apiRequest.get<UserWsKeyPair>(
|
||||
`/api/v2/workspace/${workspaceID}/encrypted-key`
|
||||
`/api/v2/workspace/${projectId}/encrypted-key`
|
||||
);
|
||||
|
||||
return data;
|
||||
|
||||
@@ -51,7 +51,7 @@ export const useAddUserToWsNonE2EE = () => {
|
||||
|
||||
return useMutation<{}, {}, AddUserToWsDTONonE2EE>({
|
||||
mutationFn: async ({ projectId, emails }) => {
|
||||
const { data } = await apiRequest.post(`/api/v3/projects/${projectId}/memberships`, {
|
||||
const { data } = await apiRequest.post(`/api/v2/workspace/${projectId}/memberships`, {
|
||||
emails
|
||||
});
|
||||
return data;
|
||||
|
||||
@@ -21,5 +21,6 @@ export {
|
||||
useToggleAutoCapitalization,
|
||||
useUpdateIdentityWorkspaceRole,
|
||||
useUpdateUserWorkspaceRole,
|
||||
useUpdateWsEnvironment
|
||||
useUpdateWsEnvironment,
|
||||
useUpgradeProject
|
||||
} from "./queries";
|
||||
|
||||
@@ -61,6 +61,21 @@ export const fetchWorkspaceSecrets = async (workspaceId: string) => {
|
||||
return secrets;
|
||||
};
|
||||
|
||||
export const useUpgradeProject = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<{}, {}, { projectId: string; privateKey: string }>({
|
||||
mutationFn: ({ projectId, privateKey }) => {
|
||||
return apiRequest.post(`/api/v2/workspace/${projectId}/upgrade`, {
|
||||
userPrivateKey: privateKey
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchUserWorkspaces = async () => {
|
||||
const { data } = await apiRequest.get<{ workspaces: Workspace[] }>("/api/v1/workspace");
|
||||
return data.workspaces;
|
||||
@@ -160,7 +175,7 @@ export const createWorkspace = ({
|
||||
organizationId,
|
||||
projectName
|
||||
}: CreateWorkspaceDTO): Promise<{ data: { project: Workspace } }> => {
|
||||
return apiRequest.post("/api/v3/projects", { projectName, organizationId });
|
||||
return apiRequest.post("/api/v2/workspace", { projectName, organizationId });
|
||||
};
|
||||
|
||||
export const useCreateWorkspace = () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ export type Workspace = {
|
||||
id: string;
|
||||
name: string;
|
||||
orgId: string;
|
||||
e2ee: boolean;
|
||||
version: "v1" | "v2";
|
||||
autoCapitalization: boolean;
|
||||
environments: WorkspaceEnv[];
|
||||
slug: string;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
/* eslint-disable vars-on-top */
|
||||
/* eslint-disable no-var */
|
||||
/* eslint-disable func-names */
|
||||
import crypto from "crypto";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
@@ -34,7 +33,6 @@ import * as yup from "yup";
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { tempLocalStorage } from "@app/components/utilities/checks/tempLocalStorage";
|
||||
import { encryptAssymmetric } from "@app/components/utilities/cryptography/crypto";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
@@ -62,16 +60,14 @@ import {
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import {
|
||||
fetchOrgUsers,
|
||||
useAddUserToWsE2EE,
|
||||
useAddUserToWsNonE2EE,
|
||||
useCreateWorkspace,
|
||||
useGetOrgTrialUrl,
|
||||
useGetSecretApprovalRequestCount,
|
||||
useGetUserAction,
|
||||
useLogoutUser,
|
||||
useRegisterUserAction,
|
||||
useUploadWsKey
|
||||
useRegisterUserAction
|
||||
} from "@app/hooks/api";
|
||||
import { fetchUserWsKey } from "@app/hooks/api/keys/queries";
|
||||
import { CreateOrgModal } from "@app/views/Org/components";
|
||||
|
||||
interface LayoutProps {
|
||||
@@ -129,8 +125,8 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
||||
: true;
|
||||
|
||||
const createWs = useCreateWorkspace();
|
||||
const uploadWsKey = useUploadWsKey();
|
||||
const addWsUser = useAddUserToWsE2EE();
|
||||
const addUsersToProject = useAddUserToWsNonE2EE();
|
||||
|
||||
const infisicalPlatformVersion = process.env.NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION;
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
@@ -220,53 +216,32 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
||||
|
||||
const onCreateProject = async ({ name, addMembers }: TAddProjectFormData) => {
|
||||
// type check
|
||||
if (!currentOrg?.id) return;
|
||||
if (!currentOrg) return;
|
||||
if (!user) return;
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
project: { id: newWorkspaceId }
|
||||
project: { id: newProjectId }
|
||||
}
|
||||
} = await createWs.mutateAsync({
|
||||
organizationId: currentOrg?.id,
|
||||
organizationId: currentOrg.id,
|
||||
projectName: name
|
||||
});
|
||||
|
||||
const randomBytes = crypto.randomBytes(16).toString("hex");
|
||||
const PRIVATE_KEY = String(localStorage.getItem("PRIVATE_KEY"));
|
||||
const { ciphertext, nonce } = encryptAssymmetric({
|
||||
plaintext: randomBytes,
|
||||
publicKey: user.publicKey,
|
||||
privateKey: PRIVATE_KEY
|
||||
});
|
||||
|
||||
await uploadWsKey.mutateAsync({
|
||||
encryptedKey: ciphertext,
|
||||
nonce,
|
||||
userId: user?.id,
|
||||
workspaceId: newWorkspaceId
|
||||
});
|
||||
|
||||
if (addMembers) {
|
||||
// not using hooks because need at this point only
|
||||
const orgUsers = await fetchOrgUsers(currentOrg.id);
|
||||
const decryptKey = await fetchUserWsKey(newWorkspaceId);
|
||||
await addWsUser.mutateAsync({
|
||||
workspaceId: newWorkspaceId,
|
||||
decryptKey,
|
||||
userPrivateKey: PRIVATE_KEY,
|
||||
members: orgUsers
|
||||
.filter(
|
||||
({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email
|
||||
)
|
||||
.map(({ user: orgUser, id: orgMembershipId }) => ({
|
||||
userPublicKey: orgUser.publicKey,
|
||||
orgMembershipId
|
||||
}))
|
||||
|
||||
await addUsersToProject.mutateAsync({
|
||||
emails: orgUsers
|
||||
.map((member) => member.user.email)
|
||||
.filter((email) => email !== user.email),
|
||||
projectId: newProjectId
|
||||
});
|
||||
}
|
||||
|
||||
createNotification({ text: "Workspace created", type: "success" });
|
||||
handlePopUpClose("addNewWs");
|
||||
router.push(`/project/${newWorkspaceId}/secrets/overview`);
|
||||
router.push(`/project/${newProjectId}/secrets/overview`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({ text: "Failed to create workspace", type: "error" });
|
||||
|
||||
@@ -117,18 +117,23 @@ export const MemberListTab = () => {
|
||||
if (!orgUser) return;
|
||||
|
||||
try {
|
||||
if (currentWorkspace.e2ee) {
|
||||
if (currentWorkspace.version === "v1") {
|
||||
await addUserToWorkspace({
|
||||
workspaceId,
|
||||
userPrivateKey,
|
||||
decryptKey: wsKey,
|
||||
members: [{ orgMembershipId, userPublicKey: orgUser.user.publicKey }]
|
||||
});
|
||||
} else {
|
||||
} else if (currentWorkspace.version === "v2") {
|
||||
await addUserToWorkspaceNonE2EE({
|
||||
projectId: workspaceId,
|
||||
emails: [orgUser.user.email]
|
||||
});
|
||||
} else {
|
||||
createNotification({
|
||||
text: "Failed to add user to project, unknown project type",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
createNotification({
|
||||
text: "Successfully added user to the project",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -14,6 +14,8 @@ import { useNotificationContext } from "@app/components/context/Notifications/No
|
||||
import NavHeader from "@app/components/navigation/NavHeader";
|
||||
import { PermissionDeniedBanner } from "@app/components/permissions";
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
Button,
|
||||
EmptyState,
|
||||
IconButton,
|
||||
@@ -37,7 +39,8 @@ import {
|
||||
useGetFoldersByEnv,
|
||||
useGetProjectSecretsAllEnv,
|
||||
useGetUserWsKey,
|
||||
useUpdateSecretV3
|
||||
useUpdateSecretV3,
|
||||
useUpgradeProject
|
||||
} from "@app/hooks/api";
|
||||
|
||||
import { FolderBreadCrumbs } from "./components/FolderBreadCrumbs";
|
||||
@@ -104,6 +107,7 @@ export const SecretOverviewPage = () => {
|
||||
environments: userAvailableEnvs.map(({ slug }) => slug)
|
||||
});
|
||||
|
||||
const upgradeProject = useUpgradeProject();
|
||||
const { mutateAsync: createSecretV3 } = useCreateSecretV3();
|
||||
const { mutateAsync: updateSecretV3 } = useUpdateSecretV3();
|
||||
const { mutateAsync: deleteSecretV3 } = useDeleteSecretV3();
|
||||
@@ -197,6 +201,24 @@ export const SecretOverviewPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const onUpgradeProject = useCallback(async () => {
|
||||
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
|
||||
|
||||
if (!PRIVATE_KEY) {
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Private key not found"
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await upgradeProject.mutateAsync({
|
||||
projectId: workspaceId,
|
||||
privateKey: PRIVATE_KEY
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleResetSearch = () => setSearchFilter("");
|
||||
|
||||
const handleFolderClick = (path: string) => {
|
||||
@@ -315,6 +337,23 @@ export const SecretOverviewPage = () => {
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{currentWorkspace?.version === "v1" && (
|
||||
<div className="mt-8">
|
||||
<Alert variant="danger">
|
||||
<AlertDescription className="prose">
|
||||
Upgrade your project. More filler text More filler text More filler text More filler
|
||||
text More filler text More filler text More filler text More filler text More filler
|
||||
text More filler text More filler text More filler text{" "}
|
||||
</AlertDescription>
|
||||
<div className="mt-2">
|
||||
<Button isLoading={upgradeProject.isLoading} onClick={onUpgradeProject}>
|
||||
Upgrade
|
||||
</Button>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-8 flex items-center justify-between">
|
||||
<FolderBreadCrumbs secretPath={secretPath} onResetSearch={handleResetSearch} />
|
||||
<div className="w-80">
|
||||
|
||||
Reference in New Issue
Block a user