mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 10:28:22 +00:00
fix: improvements
This commit is contained in:
@@ -18,14 +18,11 @@ export const registerExternalMigrationRouter = async (server: FastifyZodProvider
|
|||||||
nonce: z.string().trim().min(1),
|
nonce: z.string().trim().min(1),
|
||||||
data: z.string().trim().min(1)
|
data: z.string().trim().min(1)
|
||||||
})
|
})
|
||||||
}),
|
})
|
||||||
response: {
|
|
||||||
200: z.object({})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
await server.services.migration.importEnvnKeyData({
|
await server.services.migration.importEnvKeyData({
|
||||||
decryptionKey: req.body.decryptionKey,
|
decryptionKey: req.body.decryptionKey,
|
||||||
encryptedJson: req.body.encryptedJson,
|
encryptedJson: req.body.encryptedJson,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
|
|||||||
@@ -1,16 +1,33 @@
|
|||||||
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import sjcl from "sjcl";
|
import sjcl from "sjcl";
|
||||||
import tweetnacl from "tweetnacl";
|
import tweetnacl from "tweetnacl";
|
||||||
import tweetnaclUtil from "tweetnacl-util";
|
import tweetnaclUtil from "tweetnacl-util";
|
||||||
|
|
||||||
|
import { OrgMembershipRole, ProjectMembershipRole, SecretType } from "@app/db/schemas";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { logger } from "@app/lib/logger";
|
||||||
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
|
|
||||||
import { InfisicalImportData, TEnvKeyExportJSON } from "./external-migration-types";
|
import { TOrgServiceFactory } from "../org/org-service";
|
||||||
|
import { TProjectServiceFactory } from "../project/project-service";
|
||||||
|
import { TProjectEnvServiceFactory } from "../project-env/project-env-service";
|
||||||
|
import { TSecretServiceFactory } from "../secret/secret-service";
|
||||||
|
import { InfisicalImportData, TEnvKeyExportJSON, TImportInfisicalDataCreate } from "./external-migration-types";
|
||||||
|
|
||||||
|
export type TImportDataIntoInfisicalDTO = {
|
||||||
|
projectService: TProjectServiceFactory;
|
||||||
|
orgService: TOrgServiceFactory;
|
||||||
|
projectEnvService: TProjectEnvServiceFactory;
|
||||||
|
secretService: TSecretServiceFactory;
|
||||||
|
|
||||||
|
input: TImportInfisicalDataCreate;
|
||||||
|
};
|
||||||
|
|
||||||
const { codec, hash } = sjcl;
|
const { codec, hash } = sjcl;
|
||||||
const { secretbox } = tweetnacl;
|
const { secretbox } = tweetnacl;
|
||||||
|
|
||||||
export const decryptEnvKeyData = async (decryptionKey: string, encryptedJson: { nonce: string; data: string }) => {
|
export const decryptEnvKeyDataFn = async (decryptionKey: string, encryptedJson: { nonce: string; data: string }) => {
|
||||||
const key = tweetnaclUtil.decodeBase64(codec.base64.fromBits(hash.sha256.hash(decryptionKey)));
|
const key = tweetnaclUtil.decodeBase64(codec.base64.fromBits(hash.sha256.hash(decryptionKey)));
|
||||||
const nonce = tweetnaclUtil.decodeBase64(encryptedJson.nonce);
|
const nonce = tweetnaclUtil.decodeBase64(encryptedJson.nonce);
|
||||||
const encryptedData = tweetnaclUtil.decodeBase64(encryptedJson.data);
|
const encryptedData = tweetnaclUtil.decodeBase64(encryptedJson.data);
|
||||||
@@ -25,7 +42,7 @@ export const decryptEnvKeyData = async (decryptionKey: string, encryptedJson: {
|
|||||||
return decryptedJson;
|
return decryptedJson;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseEnvKeyData = async (decryptedJson: string): Promise<InfisicalImportData> => {
|
export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<InfisicalImportData> => {
|
||||||
const parsedJson: TEnvKeyExportJSON = JSON.parse(decryptedJson) as TEnvKeyExportJSON;
|
const parsedJson: TEnvKeyExportJSON = JSON.parse(decryptedJson) as TEnvKeyExportJSON;
|
||||||
|
|
||||||
const infisicalImportData: InfisicalImportData = {
|
const infisicalImportData: InfisicalImportData = {
|
||||||
@@ -71,3 +88,110 @@ export const parseEnvKeyData = async (decryptedJson: string): Promise<InfisicalI
|
|||||||
|
|
||||||
return infisicalImportData;
|
return infisicalImportData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const importDataIntoInfisicalFn = async ({
|
||||||
|
projectService,
|
||||||
|
orgService,
|
||||||
|
projectEnvService,
|
||||||
|
secretService,
|
||||||
|
input: { data, actor, actorId, actorOrgId, actorAuthMethod }
|
||||||
|
}: TImportDataIntoInfisicalDTO) => {
|
||||||
|
// Import data to infisical
|
||||||
|
if (!data || !data.projects) {
|
||||||
|
throw new BadRequestError({ message: "No projects found in data" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalToNewProjectId = new Map<string, string>();
|
||||||
|
const originalToNewEnvironmentId = new Map<string, string>();
|
||||||
|
|
||||||
|
for await (const [id, project] of data.projects) {
|
||||||
|
const newProject = await projectService
|
||||||
|
.createProject({
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
workspaceName: project.name,
|
||||||
|
createDefaultEnvs: false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new BadRequestError({ message: `Failed to import to project [name:${project.name}] [id:${id}]` });
|
||||||
|
});
|
||||||
|
|
||||||
|
originalToNewProjectId.set(project.id, newProject.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invite user importing projects
|
||||||
|
const invites = await orgService.inviteUserToOrganization({
|
||||||
|
actorAuthMethod,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actor,
|
||||||
|
inviteeEmails: [],
|
||||||
|
orgId: actorOrgId,
|
||||||
|
organizationRoleSlug: OrgMembershipRole.NoAccess,
|
||||||
|
projects: Array.from(originalToNewProjectId.values()).map((project) => ({
|
||||||
|
id: project,
|
||||||
|
projectRoleSlug: [ProjectMembershipRole.Member]
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
if (!invites) {
|
||||||
|
throw new BadRequestError({ message: `Failed to invite user to projects: [userId:${actorId}]` });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import environments
|
||||||
|
if (data.environments) {
|
||||||
|
for await (const [id, environment] of data.environments) {
|
||||||
|
try {
|
||||||
|
const newEnvironment = await projectEnvService.createEnvironment({
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
name: environment.name,
|
||||||
|
projectId: originalToNewProjectId.get(environment.projectId)!,
|
||||||
|
slug: slugify(`${environment.name}-${alphaNumericNanoId(4)}`)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!newEnvironment) {
|
||||||
|
logger.error(`Failed to import environment: [name:${environment.name}] [id:${id}]`);
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Failed to import environment: [name:${environment.name}] [id:${id}]`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
originalToNewEnvironmentId.set(id, newEnvironment.slug);
|
||||||
|
} catch (error) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Failed to import environment: ${environment.name}]`,
|
||||||
|
name: "EnvKeyMigrationImportEnvironment"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import secrets
|
||||||
|
if (data.secrets) {
|
||||||
|
for await (const [id, secret] of data.secrets) {
|
||||||
|
const dataProjectId = data.environments?.get(secret.environmentId)?.projectId;
|
||||||
|
if (!dataProjectId) {
|
||||||
|
throw new BadRequestError({ message: `Failed to import secret "${secret.name}", project not found` });
|
||||||
|
}
|
||||||
|
const projectId = originalToNewProjectId.get(dataProjectId);
|
||||||
|
const newSecret = await secretService.createSecretRaw({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
environment: originalToNewEnvironmentId.get(secret.environmentId)!,
|
||||||
|
actorAuthMethod,
|
||||||
|
projectId: projectId!,
|
||||||
|
secretPath: "/",
|
||||||
|
secretName: secret.name,
|
||||||
|
type: SecretType.Shared,
|
||||||
|
secretValue: secret.value
|
||||||
|
});
|
||||||
|
if (!newSecret) {
|
||||||
|
throw new BadRequestError({ message: `Failed to import secret: [name:${secret.name}] [id:${id}]` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
|
||||||
|
|
||||||
import { OrgMembershipRole, ProjectMembershipRole, SecretType } from "@app/db/schemas";
|
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
|
||||||
import { logger } from "@app/lib/logger";
|
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
|
||||||
|
|
||||||
import { TOrgServiceFactory } from "../org/org-service";
|
import { TOrgServiceFactory } from "../org/org-service";
|
||||||
import { TProjectServiceFactory } from "../project/project-service";
|
import { TProjectServiceFactory } from "../project/project-service";
|
||||||
import { TProjectEnvServiceFactory } from "../project-env/project-env-service";
|
import { TProjectEnvServiceFactory } from "../project-env/project-env-service";
|
||||||
import { TSecretServiceFactory } from "../secret/secret-service";
|
import { TSecretServiceFactory } from "../secret/secret-service";
|
||||||
import { decryptEnvKeyData, parseEnvKeyData } from "./external-migration-fns";
|
import { decryptEnvKeyDataFn, importDataIntoInfisicalFn, parseEnvKeyDataFn } from "./external-migration-fns";
|
||||||
import { TImportEnvKeyDataCreate, TImportInfisicalDataCreate } from "./external-migration-types";
|
import { TImportEnvKeyDataCreate } from "./external-migration-types";
|
||||||
|
|
||||||
type TExternalMigrationServiceFactoryDep = {
|
type TExternalMigrationServiceFactoryDep = {
|
||||||
projectService: TProjectServiceFactory;
|
projectService: TProjectServiceFactory;
|
||||||
@@ -27,128 +20,7 @@ export const externalMigrationServiceFactory = ({
|
|||||||
projectEnvService,
|
projectEnvService,
|
||||||
secretService
|
secretService
|
||||||
}: TExternalMigrationServiceFactoryDep) => {
|
}: TExternalMigrationServiceFactoryDep) => {
|
||||||
const importInfisicalData = async ({
|
const importEnvKeyData = async ({
|
||||||
data,
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actorAuthMethod
|
|
||||||
}: TImportInfisicalDataCreate) => {
|
|
||||||
// Import data to infisical
|
|
||||||
if (!data || !data.projects) {
|
|
||||||
throw new BadRequestError({ message: "No projects found in data" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const orginalToNewProjectId = new Map<string, string>();
|
|
||||||
const orginalToNewEnvironmentId = new Map<string, string>();
|
|
||||||
|
|
||||||
// Import projects
|
|
||||||
const projectPromises = [];
|
|
||||||
for (const [id, project] of data.projects) {
|
|
||||||
const projectPromise = projectService
|
|
||||||
.createProject({
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actorAuthMethod,
|
|
||||||
workspaceName: project.name,
|
|
||||||
createDefaultEnvs: false
|
|
||||||
})
|
|
||||||
.then((projectResponse) => {
|
|
||||||
if (!projectResponse) {
|
|
||||||
throw new BadRequestError({ message: `Failed to import to project [name:${project.name}] [id:${id}]` });
|
|
||||||
}
|
|
||||||
orginalToNewProjectId.set(project.id, projectResponse.id);
|
|
||||||
});
|
|
||||||
projectPromises.push(projectPromise);
|
|
||||||
}
|
|
||||||
await Promise.all(projectPromises);
|
|
||||||
|
|
||||||
// Invite user importing projects
|
|
||||||
const response = await orgService.inviteUserToOrganization({
|
|
||||||
actorAuthMethod,
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actor,
|
|
||||||
inviteeEmails: [],
|
|
||||||
orgId: actorOrgId,
|
|
||||||
organizationRoleSlug: OrgMembershipRole.NoAccess,
|
|
||||||
projects: Array.from(orginalToNewProjectId.values()).map((project) => {
|
|
||||||
return {
|
|
||||||
id: project,
|
|
||||||
projectRoleSlug: [ProjectMembershipRole.Member]
|
|
||||||
};
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if (!response) {
|
|
||||||
throw new BadRequestError({ message: `Failed to invite user to projects: [userId:${actorId}]` });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import environments
|
|
||||||
if (data.environments) {
|
|
||||||
for await (const [id, environment] of data.environments) {
|
|
||||||
try {
|
|
||||||
// TODO: we can create envs parallely once the position constraint is handled differently
|
|
||||||
const newEnvironment = await projectEnvService.createEnvironment({
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actorAuthMethod,
|
|
||||||
name: environment.name,
|
|
||||||
projectId: orginalToNewProjectId.get(environment.projectId)!,
|
|
||||||
slug: slugify(`${environment.name}-${alphaNumericNanoId(4)}`)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!newEnvironment) {
|
|
||||||
logger.error(`Failed to import environment: [name:${environment.name}] [id:${id}]`);
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Failed to import environment: [name:${environment.name}] [id:${id}]`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
orginalToNewEnvironmentId.set(id, newEnvironment.slug);
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
success: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import secrets
|
|
||||||
if (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`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: `Failed to import secret: [name:${secret.name}] [id:${id}], project not found`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const projectId = orginalToNewProjectId.get(dataProjectId);
|
|
||||||
// TODO: we can create secrets parallely once the KMS ID bug on create is fixed
|
|
||||||
const newSecret = await secretService.createSecretRaw({
|
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
actorOrgId,
|
|
||||||
environment: orginalToNewEnvironmentId.get(secret.environmentId)!,
|
|
||||||
actorAuthMethod,
|
|
||||||
projectId: projectId!,
|
|
||||||
secretPath: "/",
|
|
||||||
secretName: secret.name,
|
|
||||||
type: SecretType.Shared,
|
|
||||||
secretValue: secret.value
|
|
||||||
});
|
|
||||||
if (!newSecret) {
|
|
||||||
throw new BadRequestError({ message: `Failed to import secret: [name:${secret.name}] [id:${id}]` });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const importEnvnKeyData = async ({
|
|
||||||
decryptionKey,
|
decryptionKey,
|
||||||
encryptedJson,
|
encryptedJson,
|
||||||
actor,
|
actor,
|
||||||
@@ -156,13 +28,19 @@ export const externalMigrationServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TImportEnvKeyDataCreate) => {
|
}: TImportEnvKeyDataCreate) => {
|
||||||
const json = await decryptEnvKeyData(decryptionKey, encryptedJson);
|
const json = await decryptEnvKeyDataFn(decryptionKey, encryptedJson);
|
||||||
const envKeyData = await parseEnvKeyData(json);
|
const envKeyData = await parseEnvKeyDataFn(json);
|
||||||
const response = await importInfisicalData({ data: envKeyData, actor, actorId, actorOrgId, actorAuthMethod });
|
const response = await importDataIntoInfisicalFn({
|
||||||
|
input: { data: envKeyData, actor, actorId, actorOrgId, actorAuthMethod },
|
||||||
|
projectService,
|
||||||
|
orgService,
|
||||||
|
projectEnvService,
|
||||||
|
secretService
|
||||||
|
});
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
importEnvnKeyData
|
importEnvKeyData
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
import { OrgMembershipRole, ProjectMembershipRole, ProjectVersion } from "@app/db/schemas";
|
import { OrgMembershipRole, ProjectMembershipRole, ProjectVersion, TProjectEnvironments } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
@@ -208,15 +208,7 @@ export const projectServiceFactory = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// set default environments and root folder for provided environments
|
// set default environments and root folder for provided environments
|
||||||
let envs: {
|
let envs: TProjectEnvironments[] = [];
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
projectId: string;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
position: number;
|
|
||||||
}[] = [];
|
|
||||||
if (createDefaultEnvs) {
|
if (createDefaultEnvs) {
|
||||||
envs = await projectEnvDAL.insertMany(
|
envs = await projectEnvDAL.insertMany(
|
||||||
DEFAULT_PROJECT_ENVS.map((el, i) => ({ ...el, projectId: project.id, position: i + 1 })),
|
DEFAULT_PROJECT_ENVS.map((el, i) => ({ ...el, projectId: project.id, position: i + 1 })),
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ type TForm = z.infer<typeof formSchema>;
|
|||||||
export const ImportTab = () => {
|
export const ImportTab = () => {
|
||||||
const fileUploadRef = useRef<HTMLInputElement>(null);
|
const fileUploadRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const { mutateAsync: importEnvKey
|
const { mutateAsync: importEnvKey } = useImportEnvKey();
|
||||||
} = useImportEnvKey();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -50,11 +49,14 @@ export const ImportTab = () => {
|
|||||||
|
|
||||||
const parseJson = (src: ArrayBuffer) => {
|
const parseJson = (src: ArrayBuffer) => {
|
||||||
const file = src.toString();
|
const file = src.toString();
|
||||||
const formatedData: Record<string, string> = JSON.parse(file);
|
const formattedData: Record<string, string> = JSON.parse(file);
|
||||||
if (Object.keys(formatedData).includes("nonce") && Object.keys(formatedData).includes("data")) {
|
if (
|
||||||
|
Object.keys(formattedData).includes("nonce") &&
|
||||||
|
Object.keys(formattedData).includes("data")
|
||||||
|
) {
|
||||||
const data = {
|
const data = {
|
||||||
nonce: formatedData.nonce,
|
nonce: formattedData.nonce,
|
||||||
data: formatedData.data
|
data: formattedData.data
|
||||||
};
|
};
|
||||||
setValue("encryptedJson", data);
|
setValue("encryptedJson", data);
|
||||||
trigger("encryptedJson");
|
trigger("encryptedJson");
|
||||||
@@ -86,9 +88,9 @@ export const ImportTab = () => {
|
|||||||
if (!event?.target?.result) return;
|
if (!event?.target?.result) return;
|
||||||
// parse function's argument looks like to be ArrayBuffer
|
// parse function's argument looks like to be ArrayBuffer
|
||||||
parseJson(event.target.result as ArrayBuffer);
|
parseJson(event.target.result as ArrayBuffer);
|
||||||
}
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
};
|
||||||
|
|
||||||
const submitExport = async (data: TForm) => {
|
const submitExport = async (data: TForm) => {
|
||||||
if (!data.encryptedJson) {
|
if (!data.encryptedJson) {
|
||||||
@@ -99,7 +101,7 @@ export const ImportTab = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
await importEnvKey({ encryptedJson: data.encryptedJson, decryptionKey: data.encryptionKey });
|
await importEnvKey({ encryptedJson: data.encryptedJson, decryptionKey: data.encryptionKey });
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Data imported successfully.",
|
text: "Data imported successfully.",
|
||||||
@@ -109,11 +111,10 @@ export const ImportTab = () => {
|
|||||||
if (fileUploadRef.current) {
|
if (fileUploadRef.current) {
|
||||||
fileUploadRef.current.value = "";
|
fileUploadRef.current.value = "";
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const watchEncryptedJsonFile: any = watch("file");
|
const watchEncryptedJsonFile: any = watch("file");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -124,13 +125,13 @@ export const ImportTab = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||||
<h2 className="text-lg font-medium text-white mb-4">Import from external source</h2>
|
<h2 className="mb-4 text-lg font-medium text-white">Import from external source</h2>
|
||||||
<p className="text-sm text-mineshaft-400">
|
<p className="text-sm text-mineshaft-400">
|
||||||
Import data from another secret manager to Infisical.
|
Import data from another secret manager to Infisical.
|
||||||
</p>
|
</p>
|
||||||
<div className="border-b border-mineshaft-800 my-6" />
|
<div className="my-6 border-b border-mineshaft-800" />
|
||||||
<div className="flex justify-left">
|
<div className="justify-left flex">
|
||||||
<h3 className="text-lg font-medium text-white mb-4">Import from EnvKey</h3>
|
<h3 className="mb-4 text-lg font-medium text-white">Import from EnvKey</h3>
|
||||||
<Link href="https://infisical.com/docs/documentation/guides/migrating-from-envkey" passHref>
|
<Link href="https://infisical.com/docs/documentation/guides/migrating-from-envkey" passHref>
|
||||||
<a target="_blank" rel="noopener noreferrer">
|
<a target="_blank" rel="noopener noreferrer">
|
||||||
<div className="ml-2 mb-1 inline-block rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
|
<div className="ml-2 mb-1 inline-block rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
|
||||||
@@ -148,12 +149,16 @@ export const ImportTab = () => {
|
|||||||
<form onSubmit={handleSubmit(submitExport)}>
|
<form onSubmit={handleSubmit(submitExport)}>
|
||||||
<Controller
|
<Controller
|
||||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
<FormControl errorText={error?.message} isError={Boolean(error)} label="Encryption Key">
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
label="Encryption Key"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
{...field}
|
{...field}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
type="password"
|
type="password"
|
||||||
className="w-full bg-mineshaft-800 text-white rounded-lg py-2 px-4"
|
className="w-full rounded-lg bg-mineshaft-800 py-2 px-4 text-white"
|
||||||
placeholder="Enter encryption key"
|
placeholder="Enter encryption key"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -161,14 +166,18 @@ export const ImportTab = () => {
|
|||||||
name="encryptionKey"
|
name="encryptionKey"
|
||||||
control={control}
|
control={control}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-left">
|
<div className="justify-left flex">
|
||||||
<Controller
|
<Controller
|
||||||
name="file"
|
name="file"
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
rules={{ required: "File is required" }}
|
rules={{ required: "File is required" }}
|
||||||
render={({ field, fieldState: { error } }) => (
|
render={({ field, fieldState: { error } }) => (
|
||||||
<FormControl errorText={error?.message} isError={Boolean(error)} label="Export file from EnvKey">
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
label="Export file from EnvKey"
|
||||||
|
>
|
||||||
<>
|
<>
|
||||||
<input
|
<input
|
||||||
id="fileSelect"
|
id="fileSelect"
|
||||||
@@ -185,22 +194,22 @@ export const ImportTab = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
fileUploadRef?.current?.click();
|
fileUploadRef?.current?.click();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{fileUploadRef?.current?.value ? (
|
{fileUploadRef?.current?.value ? (
|
||||||
<span className="text-green text-sm">
|
<span className="text-sm text-green">
|
||||||
{fileUploadRef?.current?.value.split("\\").pop()}
|
{fileUploadRef?.current?.value.split("\\").pop()}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
Upload export file
|
Upload export file
|
||||||
<FontAwesomeIcon icon={faUpload} size="xs" />
|
<FontAwesomeIcon icon={faUpload} size="xs" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)} />
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user