mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 22:27:48 +00:00
327 lines
9.4 KiB
TypeScript
327 lines
9.4 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useQueries, useQuery, UseQueryOptions } from "@tanstack/react-query";
|
|
|
|
import {
|
|
decryptAssymmetric,
|
|
decryptSymmetric
|
|
} from "@app/components/utilities/cryptography/crypto";
|
|
import { apiRequest } from "@app/config/request";
|
|
|
|
import {
|
|
TGetImportedFoldersByEnvDTO,
|
|
TGetImportedSecrets,
|
|
TGetSecretImports,
|
|
TGetSecretImportsAllEnvs,
|
|
TImportedSecrets,
|
|
TSecretImport,
|
|
TuseGetImportedFoldersByEnv
|
|
} from "./types";
|
|
|
|
export const secretImportKeys = {
|
|
getProjectSecretImports: ({ environment, projectId, path }: TGetSecretImports) =>
|
|
[{ projectId, path, environment }, "secrets-imports"] as const,
|
|
getSecretImportSecrets: ({
|
|
environment,
|
|
projectId,
|
|
path
|
|
}: Omit<TGetImportedSecrets, "decryptFileKey">) =>
|
|
[{ environment, path, projectId }, "secrets-import-sec"] as const,
|
|
getImportedFoldersByEnv: ({ environment, projectId, path }: TGetImportedFoldersByEnvDTO) =>
|
|
[{ environment, projectId, path }, "imported-folders"] as const,
|
|
getImportedFoldersAllEnvs: ({ projectId, path, environment }: TGetImportedFoldersByEnvDTO) =>
|
|
[{ projectId, path, environment }, "imported-folders-all-envs"] as const
|
|
};
|
|
|
|
const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => {
|
|
const { data } = await apiRequest.get<{ secretImports: TSecretImport[] }>(
|
|
"/api/v1/secret-imports",
|
|
{
|
|
params: {
|
|
workspaceId: projectId,
|
|
environment,
|
|
path
|
|
}
|
|
}
|
|
);
|
|
return data.secretImports;
|
|
};
|
|
|
|
export const useGetSecretImports = ({
|
|
environment,
|
|
path = "/",
|
|
projectId,
|
|
options = {}
|
|
}: TGetSecretImports & {
|
|
options?: Omit<
|
|
UseQueryOptions<
|
|
TSecretImport[],
|
|
unknown,
|
|
TSecretImport[],
|
|
ReturnType<typeof secretImportKeys.getProjectSecretImports>
|
|
>,
|
|
"queryKey" | "queryFn"
|
|
>;
|
|
}) =>
|
|
useQuery({
|
|
...options,
|
|
queryKey: secretImportKeys.getProjectSecretImports({ environment, projectId, path }),
|
|
enabled: Boolean(projectId) && Boolean(environment) && (options?.enabled ?? true),
|
|
queryFn: () => fetchSecretImport({ path, projectId, environment })
|
|
});
|
|
|
|
const fetchImportedSecrets = async (
|
|
workspaceId: string,
|
|
environment: string,
|
|
directory?: string
|
|
) => {
|
|
const { data } = await apiRequest.get<{ secrets: TImportedSecrets[] }>(
|
|
"/api/v1/secret-imports/secrets",
|
|
{
|
|
params: {
|
|
workspaceId,
|
|
environment,
|
|
path: directory
|
|
}
|
|
}
|
|
);
|
|
return data.secrets;
|
|
};
|
|
|
|
const fetchImportedFolders = async ({
|
|
projectId,
|
|
environment,
|
|
path
|
|
}: TGetImportedFoldersByEnvDTO) => {
|
|
const { data } = await apiRequest.get<{ secretImports: TSecretImport[] }>(
|
|
"/api/v1/secret-imports",
|
|
{
|
|
params: {
|
|
workspaceId: projectId,
|
|
environment,
|
|
path
|
|
}
|
|
}
|
|
);
|
|
return data.secretImports;
|
|
};
|
|
|
|
export const useGetImportedSecretsSingleEnv = ({
|
|
environment,
|
|
decryptFileKey,
|
|
path,
|
|
projectId,
|
|
options = {}
|
|
}: TGetImportedSecrets & {
|
|
options?: Omit<
|
|
UseQueryOptions<
|
|
TImportedSecrets[],
|
|
unknown,
|
|
TImportedSecrets[],
|
|
ReturnType<typeof secretImportKeys.getSecretImportSecrets>
|
|
>,
|
|
"queryKey" | "queryFn"
|
|
>;
|
|
}) =>
|
|
useQuery({
|
|
enabled:
|
|
Boolean(projectId) &&
|
|
Boolean(environment) &&
|
|
Boolean(decryptFileKey) &&
|
|
(options?.enabled ?? true),
|
|
queryKey: secretImportKeys.getSecretImportSecrets({
|
|
environment,
|
|
path,
|
|
projectId
|
|
}),
|
|
queryFn: () => fetchImportedSecrets(projectId, environment, path),
|
|
select: useCallback(
|
|
(data: TImportedSecrets[]) => {
|
|
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
|
|
const latestKey = decryptFileKey;
|
|
const key = decryptAssymmetric({
|
|
ciphertext: latestKey.encryptedKey,
|
|
nonce: latestKey.nonce,
|
|
publicKey: latestKey.sender.publicKey,
|
|
privateKey: PRIVATE_KEY
|
|
});
|
|
|
|
return data.map((el) => ({
|
|
environment: el.environment,
|
|
secretPath: el.secretPath,
|
|
environmentInfo: el.environmentInfo,
|
|
folderId: el.folderId,
|
|
secrets: el.secrets.map((encSecret) => {
|
|
const secretKey = decryptSymmetric({
|
|
ciphertext: encSecret.secretKeyCiphertext,
|
|
iv: encSecret.secretKeyIV,
|
|
tag: encSecret.secretKeyTag,
|
|
key
|
|
});
|
|
|
|
const secretValue = decryptSymmetric({
|
|
ciphertext: encSecret.secretValueCiphertext,
|
|
iv: encSecret.secretValueIV,
|
|
tag: encSecret.secretValueTag,
|
|
key
|
|
});
|
|
|
|
const secretComment = decryptSymmetric({
|
|
ciphertext: encSecret.secretCommentCiphertext,
|
|
iv: encSecret.secretCommentIV,
|
|
tag: encSecret.secretCommentTag,
|
|
key
|
|
});
|
|
|
|
return {
|
|
id: encSecret.id,
|
|
env: encSecret.environment,
|
|
key: secretKey,
|
|
value: secretValue,
|
|
tags: encSecret.tags,
|
|
comment: secretComment,
|
|
createdAt: encSecret.createdAt,
|
|
updatedAt: encSecret.updatedAt,
|
|
version: encSecret.version
|
|
};
|
|
})
|
|
}));
|
|
},
|
|
[decryptFileKey]
|
|
)
|
|
});
|
|
|
|
export const useGetImportedSecretsAllEnvs = ({
|
|
projectId,
|
|
environments,
|
|
path = "/",
|
|
decryptFileKey
|
|
}: TGetSecretImportsAllEnvs) => {
|
|
const secretImports = useQueries({
|
|
queries: environments.map((env) => ({
|
|
queryKey: secretImportKeys.getImportedFoldersAllEnvs({
|
|
environment: env,
|
|
projectId,
|
|
path
|
|
}),
|
|
queryFn: () => fetchImportedSecrets(projectId, env, path).catch(() => []),
|
|
enabled: Boolean(projectId) && Boolean(env),
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
select: useCallback(
|
|
(data: TImportedSecrets[]) => {
|
|
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
|
|
const latestKey = decryptFileKey;
|
|
const key = decryptAssymmetric({
|
|
ciphertext: latestKey.encryptedKey,
|
|
nonce: latestKey.nonce,
|
|
publicKey: latestKey.sender.publicKey,
|
|
privateKey: PRIVATE_KEY
|
|
});
|
|
|
|
return data.map((el) => ({
|
|
environment: el.environment,
|
|
secretPath: el.secretPath,
|
|
environmentInfo: el.environmentInfo,
|
|
folderId: el.folderId,
|
|
secrets: el.secrets.map((encSecret) => {
|
|
const secretKey = decryptSymmetric({
|
|
ciphertext: encSecret.secretKeyCiphertext,
|
|
iv: encSecret.secretKeyIV,
|
|
tag: encSecret.secretKeyTag,
|
|
key
|
|
});
|
|
|
|
const secretValue = decryptSymmetric({
|
|
ciphertext: encSecret.secretValueCiphertext,
|
|
iv: encSecret.secretValueIV,
|
|
tag: encSecret.secretValueTag,
|
|
key
|
|
});
|
|
|
|
const secretComment = decryptSymmetric({
|
|
ciphertext: encSecret.secretCommentCiphertext,
|
|
iv: encSecret.secretCommentIV,
|
|
tag: encSecret.secretCommentTag,
|
|
key
|
|
});
|
|
|
|
return {
|
|
id: encSecret.id,
|
|
env: encSecret.environment,
|
|
key: secretKey,
|
|
value: secretValue,
|
|
tags: encSecret.tags,
|
|
comment: secretComment,
|
|
createdAt: encSecret.createdAt,
|
|
updatedAt: encSecret.updatedAt,
|
|
version: encSecret.version
|
|
};
|
|
})
|
|
}));
|
|
},
|
|
[decryptFileKey]
|
|
)
|
|
}))
|
|
});
|
|
|
|
const isImportedSecretPresentInEnv = useCallback(
|
|
(secPath: string, envSlug: string, secretName: string) => {
|
|
const selectedEnvIndex = environments.indexOf(envSlug);
|
|
|
|
if (selectedEnvIndex !== -1) {
|
|
const isPresent = secretImports?.[selectedEnvIndex]?.data?.find(
|
|
({ secretPath, ...rest }) =>
|
|
secretPath === secPath && rest.secrets.some((s) => s.key === secretName)
|
|
);
|
|
|
|
return Boolean(isPresent);
|
|
}
|
|
return false;
|
|
},
|
|
[(secretImports || []).map((response) => response.data)]
|
|
);
|
|
|
|
return { secretImports, isImportedSecretPresentInEnv };
|
|
};
|
|
|
|
export const useGetImportedFoldersByEnv = ({
|
|
projectId,
|
|
environments,
|
|
path = "/"
|
|
}: TuseGetImportedFoldersByEnv) => {
|
|
const queryParams = new URLSearchParams(window.location.search);
|
|
|
|
const currentPath = path;
|
|
|
|
const importedFolders = useQueries({
|
|
queries: environments.map((env) => ({
|
|
queryKey: secretImportKeys.getImportedFoldersByEnv({
|
|
projectId,
|
|
environment: env,
|
|
path: currentPath
|
|
}),
|
|
queryFn: async () => fetchImportedFolders({ projectId, environment: env, path: currentPath }),
|
|
enabled: Boolean(projectId) && Boolean(env)
|
|
}))
|
|
});
|
|
|
|
const isImportedFolderPresentInEnv = useCallback(
|
|
(name: string, env: string) => {
|
|
const selectedEnvIndex = environments.indexOf(env);
|
|
|
|
if (selectedEnvIndex !== -1) {
|
|
const currentlyBrowsingPath = queryParams.get("secretPath") || "";
|
|
|
|
const isPresent = importedFolders?.[selectedEnvIndex]?.data?.find(
|
|
({ importPath }) => importPath === `${currentlyBrowsingPath}/${name}`
|
|
);
|
|
|
|
return Boolean(isPresent);
|
|
}
|
|
return false;
|
|
},
|
|
[(importedFolders || []).map((response) => response.data)]
|
|
);
|
|
|
|
return { importedFolders, isImportedFolderPresentInEnv };
|
|
};
|