diff --git a/backend/package-lock.json b/backend/package-lock.json index 7cf7e40b8..6ec28ed63 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -37,7 +37,6 @@ "@slack/oauth": "^3.0.1", "@slack/web-api": "^7.3.4", "@team-plain/typescript-sdk": "^4.6.1", - "@types/sjcl": "^1.0.34", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -119,6 +118,7 @@ "@types/prompt-sync": "^4.2.3", "@types/resolve": "^1.20.6", "@types/safe-regex": "^1.1.6", + "@types/sjcl": "^1.0.34", "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.20.0", "@typescript-eslint/parser": "^6.20.0", @@ -7302,6 +7302,7 @@ "version": "1.0.34", "resolved": "https://registry.npmjs.org/@types/sjcl/-/sjcl-1.0.34.tgz", "integrity": "sha512-bQHEeK5DTQRunIfQeUMgtpPsNNCcZyQ9MJuAfW1I7iN0LDunTc78Fu17STbLMd7KiEY/g2zHVApippa70h6HoQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/uuid": { diff --git a/backend/package.json b/backend/package.json index 74b210c05..217817edf 100644 --- a/backend/package.json +++ b/backend/package.json @@ -80,6 +80,7 @@ "@types/prompt-sync": "^4.2.3", "@types/resolve": "^1.20.6", "@types/safe-regex": "^1.1.6", + "@types/sjcl": "^1.0.34", "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.20.0", "@typescript-eslint/parser": "^6.20.0", @@ -134,7 +135,6 @@ "@slack/oauth": "^3.0.1", "@slack/web-api": "^7.3.4", "@team-plain/typescript-sdk": "^4.6.1", - "@types/sjcl": "^1.0.34", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", diff --git a/backend/src/server/routes/v3/external-migration-router.ts b/backend/src/server/routes/v3/external-migration-router.ts index f58b18d2b..4577da97a 100644 --- a/backend/src/server/routes/v3/external-migration-router.ts +++ b/backend/src/server/routes/v3/external-migration-router.ts @@ -7,7 +7,7 @@ import { AuthMode } from "@app/services/auth/auth-type"; export const registerExternalMigrationRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/envkey", + url: "/env-key", config: { rateLimit: readLimit }, @@ -20,15 +20,12 @@ export const registerExternalMigrationRouter = async (server: FastifyZodProvider }) }), response: { - 200: z.object({ - success: z.boolean(), - error: z.string().optional() - }) + 200: z.object({}) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const result = await server.services.migration.importEnvnKeyData({ + await server.services.migration.importEnvnKeyData({ decryptionKey: req.body.decryptionKey, encryptedJson: req.body.encryptedJson, actorId: req.permission.id, @@ -36,7 +33,6 @@ export const registerExternalMigrationRouter = async (server: FastifyZodProvider actorOrgId: req.permission.orgId, actorAuthMethod: req.permission.authMethod }); - return result; } }); }; diff --git a/backend/src/services/external-migration/external-migration-fns.ts b/backend/src/services/external-migration/external-migration-fns.ts index 9d12f5767..de2c8a390 100644 --- a/backend/src/services/external-migration/external-migration-fns.ts +++ b/backend/src/services/external-migration/external-migration-fns.ts @@ -3,6 +3,8 @@ import sjcl from "sjcl"; import tweetnacl from "tweetnacl"; import tweetnaclUtil from "tweetnacl-util"; +import { BadRequestError } from "@app/lib/errors"; + import { InfisicalImportData, TEnvKeyExportJSON } from "./external-migration-types"; const { codec, hash } = sjcl; @@ -16,7 +18,7 @@ export const decryptEnvKeyData = async (decryptionKey: string, encryptedJson: { const decrypted = secretbox.open(encryptedData, nonce, key); if (!decrypted) { - throw new Error("Decryption failed, please check the entered encryption key"); + throw new BadRequestError({ message: "Decryption failed, please check the entered encryption key" }); } const decryptedJson = tweetnaclUtil.encodeUTF8(decrypted); @@ -33,7 +35,7 @@ export const parseEnvKeyData = async (decryptedJson: string): Promise { - infisicalImportData.projects?.set(app.id, { name: app.name, id: app.id }); + infisicalImportData.projects.set(app.id, { name: app.name, id: app.id }); }); // string to string map for env templates diff --git a/backend/src/services/external-migration/external-migration-service.ts b/backend/src/services/external-migration/external-migration-service.ts index e3da0b9eb..bbb464064 100644 --- a/backend/src/services/external-migration/external-migration-service.ts +++ b/backend/src/services/external-migration/external-migration-service.ts @@ -36,11 +36,7 @@ export const externalMigrationServiceFactory = ({ }: TImportInfisicalDataCreate) => { // Import data to infisical if (!data || !data.projects) { - logger.error("No projects found in data"); - return { - success: false, - message: "No projects found in data" - }; + throw new BadRequestError({ message: "No projects found in data" }); } const orginalToNewProjectId = new Map(); @@ -55,13 +51,12 @@ export const externalMigrationServiceFactory = ({ actorId, actorOrgId, actorAuthMethod, - workspaceName: project?.name, + workspaceName: project.name, createDefaultEnvs: false }) .then((projectResponse) => { if (!projectResponse) { - logger.error(`Failed to import project: [name:${project.name}] [id:${id}]`); - throw new Error(`Failed to import project: [name:${project.name}] [id:${id}]`); + throw new BadRequestError({ message: `Failed to import to project [name:${project.name}] [id:${id}]` }); } orginalToNewProjectId.set(project.id, projectResponse.id); }); @@ -86,19 +81,14 @@ export const externalMigrationServiceFactory = ({ }) }); if (!response) { - logger.error(`Failed to invite user to projects: [userId:${actorId}]`); - return { - success: false, - message: `Failed to invite user to project: [userId:${actorId}]` - }; + throw new BadRequestError({ message: `Failed to invite user to projects: [userId:${actorId}]` }); } // Import environments if (data.environments) { - for (const [id, environment] of data.environments) { + for await (const [id, environment] of data.environments) { try { // TODO: we can create envs parallely once the position constraint is handled differently - // eslint-disable-next-line const newEnvironment = await projectEnvService.createEnvironment({ actor, actorId, @@ -126,7 +116,7 @@ export const externalMigrationServiceFactory = ({ // Import secrets if (data.secrets) { - for (const [id, secret] of data.secrets) { + for await (const [id, secret] of data.secrets) { const dataProjectId = data.environments?.get(secret.environmentId)?.projectId; if (!dataProjectId) { logger.error(`Failed to import secret: [name:${secret.name}] [id:${id}], project not found`); @@ -137,7 +127,6 @@ export const externalMigrationServiceFactory = ({ } const projectId = orginalToNewProjectId.get(dataProjectId); // TODO: we can create secrets parallely once the KMS ID bug on create is fixed - // eslint-disable-next-line const newSecret = await secretService.createSecretRaw({ actorId, actor, @@ -151,18 +140,12 @@ export const externalMigrationServiceFactory = ({ secretValue: secret.value }); if (!newSecret) { - logger.error(`Failed to import secret: [name:${secret.name}] [id:${id}]`); - return { - success: false, - message: `Failed to import secret: [name:${secret.name}] [id:${id}]` - }; + throw new BadRequestError({ message: `Failed to import secret: [name:${secret.name}] [id:${id}]` }); } } } - return { - success: true - }; + return true; }; const importEnvnKeyData = async ({ diff --git a/backend/src/services/external-migration/external-migration-types.ts b/backend/src/services/external-migration/external-migration-types.ts index ee8a1453e..cb58ad9a2 100644 --- a/backend/src/services/external-migration/external-migration-types.ts +++ b/backend/src/services/external-migration/external-migration-types.ts @@ -1,7 +1,7 @@ import { ActorAuthMethod, ActorType } from "../auth/auth-type"; export type InfisicalImportData = { - projects?: Map; + projects: Map; environments?: Map< string, diff --git a/backend/src/services/project/project-service.ts b/backend/src/services/project/project-service.ts index efb958e31..f3868d0be 100644 --- a/backend/src/services/project/project-service.ts +++ b/backend/src/services/project/project-service.ts @@ -208,7 +208,15 @@ export const projectServiceFactory = ({ ); // set default environments and root folder for provided environments - let envs; + let envs: { + id: string; + createdAt: Date; + updatedAt: Date; + projectId: string; + name: string; + slug: string; + position: number; + }[] = []; if (createDefaultEnvs) { envs = await projectEnvDAL.insertMany( DEFAULT_PROJECT_ENVS.map((el, i) => ({ ...el, projectId: project.id, position: i + 1 })), @@ -364,7 +372,7 @@ export const projectServiceFactory = ({ return { ...project, - environments: envs || [], + environments: envs, _id: project.id }; }); diff --git a/frontend/src/hooks/api/migration/mutations.tsx b/frontend/src/hooks/api/migration/mutations.tsx index 83408bba3..096345c3a 100644 --- a/frontend/src/hooks/api/migration/mutations.tsx +++ b/frontend/src/hooks/api/migration/mutations.tsx @@ -1,31 +1,27 @@ -import { useMutation } from "@tanstack/react-query"; -import { AxiosError } from "axios"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; +import { workspaceKeys } from "../workspace"; + export const useImportEnvKey = () => { + const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async ({ encryptedJson, decryptionKey }: { encryptedJson: { - nonce: string, - data: string - }, decryptionKey: string }) : Promise<{ success: boolean, message:string }>=> { - try{ - const { data } = await apiRequest.post<{ - success: boolean, - message: string - }>("/api/v3/migrate/envkey/", { - encryptedJson, - decryptionKey - }); - return data; - } catch (err) { - if ((err as AxiosError<{ - message: string - }>).response) { - return { success: false, message: (err as AxiosError<{message: string}>).response?.data?.message as string}; - } - } - return { success: false, message: "Something went wrong" }; + mutationFn: async ({ encryptedJson, decryptionKey }: { + encryptedJson: { + nonce: string, + data: string + }, decryptionKey: string + }): Promise<{ success: boolean, message: string }> => { + const { data } = await apiRequest.post("/api/v3/migrate/env-key/", { + encryptedJson, + decryptionKey + }); + return data; + }, + onSuccess: () => { + queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); } }); }; \ No newline at end of file diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/ImportTab/ImportTab.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/ImportTab/ImportTab.tsx index 7f9dd056a..0c444750c 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/ImportTab/ImportTab.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/ImportTab/ImportTab.tsx @@ -11,7 +11,7 @@ import { Button, FormControl, IconButton } from "@app/components/v2"; import { useImportEnvKey } from "@app/hooks/api/migration/mutations"; const formSchema = z.object({ - decryptionKey: z.string().min(1), + encryptionKey: z.string().min(1), file: z.unknown(), encryptedJson: z.object({ nonce: z.string().min(1), @@ -39,7 +39,7 @@ export const ImportTab = () => { } = useForm({ resolver: zodResolver(formSchema), values: { - decryptionKey: "", + encryptionKey: "", encryptedJson: { nonce: "", data: "" @@ -49,7 +49,6 @@ export const ImportTab = () => { }); const parseJson = (src: ArrayBuffer) => { - console.log("here") const file = src.toString(); const formatedData: Record = JSON.parse(file); if (Object.keys(formatedData).includes("nonce") && Object.keys(formatedData).includes("data")) { @@ -59,7 +58,6 @@ export const ImportTab = () => { }; setValue("encryptedJson", data); trigger("encryptedJson"); - console.log(data); } else { setValue("encryptedJson", { nonce: "", @@ -101,8 +99,8 @@ export const ImportTab = () => { return; } - const res = await importEnvKey({ encryptedJson: data.encryptedJson, decryptionKey: data.decryptionKey }); - if (res.success) { + try{ + await importEnvKey({ encryptedJson: data.encryptedJson, decryptionKey: data.encryptionKey }); createNotification({ text: "Data imported successfully.", type: "success" @@ -111,12 +109,10 @@ export const ImportTab = () => { if (fileUploadRef.current) { fileUploadRef.current.value = ""; } - } else { - createNotification({ - text: res.message, - type: "error" - }); + } catch (error) { + reset(); } + } const watchEncryptedJsonFile: any = watch("file"); @@ -152,17 +148,17 @@ export const ImportTab = () => {
( - + )} - name="decryptionKey" + name="encryptionKey" control={control} />