Wired most of the frontend to support ghost users

This commit is contained in:
Daniel Hougaard
2024-02-06 03:17:33 +04:00
parent fe21ba0e54
commit ccc409e9cd
9 changed files with 80 additions and 52 deletions

View File

@@ -22,7 +22,7 @@ export * from "./secrets/types";
export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types"; export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types";
export type { SubscriptionPlan } from "./subscriptions/types"; export type { SubscriptionPlan } from "./subscriptions/types";
export type { WsTag } from "./tags/types"; export type { WsTag } from "./tags/types";
export type { AddUserToWsDTO, OrgUser, TWorkspaceUser, User, UserEnc } from "./users/types"; export type { AddUserToWsDTOE2EE, OrgUser, TWorkspaceUser, User, UserEnc } from "./users/types";
export type { TWebhook } from "./webhooks/types"; export type { TWebhook } from "./webhooks/types";
export type { export type {
CreateEnvironmentDTO, CreateEnvironmentDTO,

View File

@@ -1,4 +1,4 @@
export { useAddUserToWs } from "./mutation"; export { useAddUserToWsE2EE, useAddUserToWsNonE2EE } from "./mutation";
export { export {
fetchOrgUsers, fetchOrgUsers,
useAddUserToOrg, useAddUserToOrg,

View File

@@ -7,12 +7,12 @@ import {
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
import { workspaceKeys } from "../workspace/queries"; import { workspaceKeys } from "../workspace/queries";
import { AddUserToWsDTO } from "./types"; import { AddUserToWsDTOE2EE, AddUserToWsDTONonE2EE } from "./types";
export const useAddUserToWs = () => { export const useAddUserToWsE2EE = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation<{}, {}, AddUserToWsDTO>({ return useMutation<{}, {}, AddUserToWsDTOE2EE>({
mutationFn: async ({ workspaceId, members, decryptKey, userPrivateKey }) => { mutationFn: async ({ workspaceId, members, decryptKey, userPrivateKey }) => {
// assymmetrically decrypt symmetric key with local private key // assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({ const key = decryptAssymmetric({
@@ -45,3 +45,19 @@ export const useAddUserToWs = () => {
} }
}); });
}; };
export const useAddUserToWsNonE2EE = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, AddUserToWsDTONonE2EE>({
mutationFn: async ({ projectId, emails }) => {
const { data } = await apiRequest.post(`/api/v3/projects/${projectId}/memberships`, {
emails
});
return data;
},
onSuccess: (_, { projectId }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(projectId));
}
});
};

View File

@@ -63,7 +63,7 @@ export type TProjectMembership = {
export type TWorkspaceUser = OrgUser; export type TWorkspaceUser = OrgUser;
export type AddUserToWsDTO = { export type AddUserToWsDTOE2EE = {
workspaceId: string; workspaceId: string;
decryptKey: UserWsKeyPair; decryptKey: UserWsKeyPair;
userPrivateKey: string; userPrivateKey: string;
@@ -73,6 +73,11 @@ export type AddUserToWsDTO = {
}[]; }[];
}; };
export type AddUserToWsDTONonE2EE = {
projectId: string;
emails: string[];
};
export type UpdateOrgUserRoleDTO = { export type UpdateOrgUserRoleDTO = {
organizationId: string; organizationId: string;
membershipId: string; membershipId: string;

View File

@@ -158,21 +158,19 @@ export const useGetWorkspaceIntegrations = (workspaceId: string) =>
export const createWorkspace = ({ export const createWorkspace = ({
organizationId, organizationId,
projectName, projectName
inviteAllOrgMembers }: CreateWorkspaceDTO): Promise<{ data: { project: Workspace } }> => {
}: CreateWorkspaceDTO): Promise<{ data: { workspace: Workspace } }> => { return apiRequest.post("/api/v3/projects", { projectName, organizationId });
return apiRequest.post("/api/v3/projects", { projectName, inviteAllOrgMembers, organizationId });
}; };
export const useCreateWorkspace = () => { export const useCreateWorkspace = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation<{ data: { workspace: Workspace } }, {}, CreateWorkspaceDTO>({ return useMutation<{ data: { project: Workspace } }, {}, CreateWorkspaceDTO>({
mutationFn: async ({ organizationId, projectName, inviteAllOrgMembers }) => mutationFn: async ({ organizationId, projectName }) =>
createWorkspace({ createWorkspace({
organizationId, organizationId,
projectName, projectName
inviteAllOrgMembers
}), }),
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
@@ -287,11 +285,13 @@ export const useAddUserToWorkspace = () => {
return useMutation({ return useMutation({
mutationFn: async ({ email, workspaceId }: { email: string; workspaceId: string }) => { mutationFn: async ({ email, workspaceId }: { email: string; workspaceId: string }) => {
const { const {
data: { invitee, latestKey } data: { invitees, latestKey }
} = await apiRequest.post(`/api/v1/workspace/${workspaceId}/invite-signup`, { email }); } = await apiRequest.post(`/api/v1/workspace/${workspaceId}/invite-signup`, {
emails: [email]
});
return { return {
invitee, invitees,
latestKey latestKey
}; };
}, },

View File

@@ -3,6 +3,7 @@ export type Workspace = {
id: string; id: string;
name: string; name: string;
orgId: string; orgId: string;
e2ee: boolean;
autoCapitalization: boolean; autoCapitalization: boolean;
environments: WorkspaceEnv[]; environments: WorkspaceEnv[];
}; };
@@ -26,7 +27,6 @@ export type NameWorkspaceSecretsDTO = {
// mutation dto // mutation dto
export type CreateWorkspaceDTO = { export type CreateWorkspaceDTO = {
projectName: string; projectName: string;
inviteAllOrgMembers: boolean;
organizationId: string; organizationId: string;
}; };

View File

@@ -62,7 +62,7 @@ import {
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { import {
fetchOrgUsers, fetchOrgUsers,
useAddUserToWs, useAddUserToWsE2EE,
useCreateWorkspace, useCreateWorkspace,
useGetOrgTrialUrl, useGetOrgTrialUrl,
useGetSecretApprovalRequestCount, useGetSecretApprovalRequestCount,
@@ -130,7 +130,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
const createWs = useCreateWorkspace(); const createWs = useCreateWorkspace();
const uploadWsKey = useUploadWsKey(); const uploadWsKey = useUploadWsKey();
const addWsUser = useAddUserToWs(); const addWsUser = useAddUserToWsE2EE();
const infisicalPlatformVersion = process.env.NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION; const infisicalPlatformVersion = process.env.NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION;
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
@@ -224,11 +224,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
try { try {
const { const {
data: { data: {
workspace: { id: newWorkspaceId } project: { id: newWorkspaceId }
} }
} = await createWs.mutateAsync({ } = await createWs.mutateAsync({
organizationId: currentOrg?.id, organizationId: currentOrg?.id,
workspaceName: name projectName: name
}); });
const randomBytes = crypto.randomBytes(16).toString("hex"); const randomBytes = crypto.randomBytes(16).toString("hex");

View File

@@ -53,7 +53,7 @@ import {
// fetchOrgUsers, // fetchOrgUsers,
// useAddUserToWs, // useAddUserToWs,
useCreateWorkspace, useCreateWorkspace,
useRegisterUserAction, useRegisterUserAction
} from "@app/hooks/api"; } from "@app/hooks/api";
// import { fetchUserWsKey } from "@app/hooks/api/keys/queries"; // import { fetchUserWsKey } from "@app/hooks/api/keys/queries";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails"; import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
@@ -471,7 +471,7 @@ const OrganizationPage = withPermission(
const currentOrg = String(router.query.id); const currentOrg = String(router.query.id);
const orgWorkspaces = workspaces?.filter((workspace) => workspace.orgId === currentOrg) || []; const orgWorkspaces = workspaces?.filter((workspace) => workspace.orgId === currentOrg) || [];
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
// const addWsUser = useAddUserToWs(); // const addWsUser = useAddUserToWs();
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"addNewWs", "addNewWs",
@@ -501,35 +501,32 @@ const OrganizationPage = withPermission(
try { try {
const { const {
data: { data: {
workspace: { id: newWorkspaceId } project: { id: newWorkspaceId }
} }
} = await createWs.mutateAsync({ } = await createWs.mutateAsync({
organizationId: currentOrg, organizationId: currentOrg,
inviteAllOrgMembers: addMembers,
projectName: name projectName: name
}); });
/*
if (addMembers) { if (addMembers) {
// not using hooks because need at this point only // not using hooks because need at this point only
const orgUsers = await fetchOrgUsers(currentOrg); // const orgUsers = await fetchOrgUsers(currentOrg);
const decryptKey = await fetchUserWsKey(newWorkspaceId); // const decryptKey = await fetchUserWsKey(newWorkspaceId);
// await addWsUser.mutateAsync({
await addWsUser.mutateAsync({ // workspaceId: newWorkspaceId,
workspaceId: newWorkspaceId, // decryptKey,
decryptKey, // userPrivateKey: PRIVATE_KEY,
userPrivateKey: PRIVATE_KEY, // members: orgUsers
members: orgUsers // .filter(
.filter( // ({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email
({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email // )
) // .map(({ user: orgUser, id: orgMembershipId }) => ({
.map(({ user: orgUser, id: orgMembershipId }) => ({ // userPublicKey: orgUser.publicKey,
userPublicKey: orgUser.publicKey, // orgMembershipId
orgMembershipId // }))
})) // });
});
} }
*/
createNotification({ text: "Workspace created", type: "success" }); createNotification({ text: "Workspace created", type: "success" });
handlePopUpClose("addNewWs"); handlePopUpClose("addNewWs");
router.push(`/project/${newWorkspaceId}/secrets/overview`); router.push(`/project/${newWorkspaceId}/secrets/overview`);

View File

@@ -44,7 +44,8 @@ import {
} from "@app/context"; } from "@app/context";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { import {
useAddUserToWs, useAddUserToWsE2EE,
useAddUserToWsNonE2EE,
useDeleteUserFromWorkspace, useDeleteUserFromWorkspace,
useGetOrgUsers, useGetOrgUsers,
useGetProjectRoles, useGetProjectRoles,
@@ -95,12 +96,14 @@ export const MemberListTab = () => {
formState: { isSubmitting } formState: { isSubmitting }
} = useForm<TAddMemberForm>({ resolver: zodResolver(addMemberFormSchema) }); } = useForm<TAddMemberForm>({ resolver: zodResolver(addMemberFormSchema) });
const { mutateAsync: addUserToWorkspace } = useAddUserToWs(); const { mutateAsync: addUserToWorkspace } = useAddUserToWsE2EE();
const { mutateAsync: addUserToWorkspaceNonE2EE } = useAddUserToWsNonE2EE();
const { mutateAsync: uploadWsKey } = useUploadWsKey(); const { mutateAsync: uploadWsKey } = useUploadWsKey();
const { mutateAsync: removeUserFromWorkspace } = useDeleteUserFromWorkspace(); const { mutateAsync: removeUserFromWorkspace } = useDeleteUserFromWorkspace();
const { mutateAsync: updateUserWorkspaceRole } = useUpdateUserWorkspaceRole(); const { mutateAsync: updateUserWorkspaceRole } = useUpdateUserWorkspaceRole();
const onAddMember = async ({ orgMembershipId }: TAddMemberForm) => { const onAddMember = async ({ orgMembershipId }: TAddMemberForm) => {
if (!currentWorkspace) return;
if (!currentOrg?.id) return; if (!currentOrg?.id) return;
// TODO(akhilmhdh): Move to memory storage // TODO(akhilmhdh): Move to memory storage
const userPrivateKey = localStorage.getItem("PRIVATE_KEY"); const userPrivateKey = localStorage.getItem("PRIVATE_KEY");
@@ -114,12 +117,19 @@ export const MemberListTab = () => {
if (!orgUser) return; if (!orgUser) return;
try { try {
await addUserToWorkspace({ if (currentWorkspace.e2ee) {
workspaceId, await addUserToWorkspace({
userPrivateKey, workspaceId,
decryptKey: wsKey, userPrivateKey,
members: [{ orgMembershipId, userPublicKey: orgUser.user.publicKey }] decryptKey: wsKey,
}); members: [{ orgMembershipId, userPublicKey: orgUser.user.publicKey }]
});
} else {
await addUserToWorkspaceNonE2EE({
projectId: workspaceId,
emails: [orgUser.user.email]
});
}
createNotification({ createNotification({
text: "Successfully added user to the project", text: "Successfully added user to the project",
type: "success" type: "success"