mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 13:26:31 +00:00
fix: cleanup and bug fixes
This commit is contained in:
@@ -165,6 +165,7 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
||||||
|
|
||||||
const shouldUseBridge = snapshot.projectVersion === 3;
|
const shouldUseBridge = snapshot.projectVersion === 3;
|
||||||
let snapshotDetails;
|
let snapshotDetails;
|
||||||
if (shouldUseBridge) {
|
if (shouldUseBridge) {
|
||||||
@@ -173,68 +174,93 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
projectId: snapshot.projectId
|
projectId: snapshot.projectId
|
||||||
});
|
});
|
||||||
const encryptedSnapshotDetails = await snapshotDAL.findSecretSnapshotV2DataById(id);
|
const encryptedSnapshotDetails = await snapshotDAL.findSecretSnapshotV2DataById(id);
|
||||||
|
|
||||||
|
const fullFolderPath = await getFullFolderPath({
|
||||||
|
folderDAL,
|
||||||
|
folderId: encryptedSnapshotDetails.folderId,
|
||||||
|
envId: encryptedSnapshotDetails.environment.id
|
||||||
|
});
|
||||||
|
|
||||||
snapshotDetails = {
|
snapshotDetails = {
|
||||||
...encryptedSnapshotDetails,
|
...encryptedSnapshotDetails,
|
||||||
secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => ({
|
secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => {
|
||||||
...el,
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
secretKey: el.key,
|
ProjectPermissionSecretActions.ReadValue,
|
||||||
secretValue: el.encryptedValue
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString()
|
environment: encryptedSnapshotDetails.environment.slug,
|
||||||
: "",
|
secretPath: fullFolderPath,
|
||||||
secretComment: el.encryptedComment
|
secretName: el.key,
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined
|
||||||
: ""
|
})
|
||||||
}))
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...el,
|
||||||
|
secretKey: el.key,
|
||||||
|
secretValue: el.encryptedValue
|
||||||
|
? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString()
|
||||||
|
: "",
|
||||||
|
secretComment: el.encryptedComment
|
||||||
|
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
||||||
|
: ""
|
||||||
|
};
|
||||||
|
})
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const encryptedSnapshotDetails = await snapshotDAL.findSecretSnapshotDataById(id);
|
const encryptedSnapshotDetails = await snapshotDAL.findSecretSnapshotDataById(id);
|
||||||
|
|
||||||
|
const fullFolderPath = await getFullFolderPath({
|
||||||
|
folderDAL,
|
||||||
|
folderId: encryptedSnapshotDetails.folderId,
|
||||||
|
envId: encryptedSnapshotDetails.environment.id
|
||||||
|
});
|
||||||
|
|
||||||
const { botKey } = await projectBotService.getBotKey(snapshot.projectId);
|
const { botKey } = await projectBotService.getBotKey(snapshot.projectId);
|
||||||
if (!botKey)
|
if (!botKey)
|
||||||
throw new NotFoundError({ message: `Project bot key not found for project with ID '${snapshot.projectId}'` });
|
throw new NotFoundError({ message: `Project bot key not found for project with ID '${snapshot.projectId}'` });
|
||||||
snapshotDetails = {
|
snapshotDetails = {
|
||||||
...encryptedSnapshotDetails,
|
...encryptedSnapshotDetails,
|
||||||
secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => ({
|
secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => {
|
||||||
...el,
|
const secretKey = decryptSymmetric128BitHexKeyUTF8({
|
||||||
secretKey: decryptSymmetric128BitHexKeyUTF8({
|
|
||||||
ciphertext: el.secretKeyCiphertext,
|
ciphertext: el.secretKeyCiphertext,
|
||||||
iv: el.secretKeyIV,
|
iv: el.secretKeyIV,
|
||||||
tag: el.secretKeyTag,
|
tag: el.secretKeyTag,
|
||||||
key: botKey
|
key: botKey
|
||||||
}),
|
});
|
||||||
secretValue: decryptSymmetric128BitHexKeyUTF8({
|
|
||||||
ciphertext: el.secretValueCiphertext,
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
iv: el.secretValueIV,
|
ProjectPermissionSecretActions.ReadValue,
|
||||||
tag: el.secretValueTag,
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
key: botKey
|
environment: encryptedSnapshotDetails.environment.slug,
|
||||||
}),
|
secretPath: fullFolderPath,
|
||||||
secretComment:
|
secretName: secretKey,
|
||||||
el.secretCommentTag && el.secretCommentIV && el.secretCommentCiphertext
|
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined
|
||||||
? decryptSymmetric128BitHexKeyUTF8({
|
})
|
||||||
ciphertext: el.secretCommentCiphertext,
|
);
|
||||||
iv: el.secretCommentIV,
|
|
||||||
tag: el.secretCommentTag,
|
return {
|
||||||
key: botKey
|
...el,
|
||||||
})
|
secretKey,
|
||||||
: ""
|
secretValue: decryptSymmetric128BitHexKeyUTF8({
|
||||||
}))
|
ciphertext: el.secretValueCiphertext,
|
||||||
|
iv: el.secretValueIV,
|
||||||
|
tag: el.secretValueTag,
|
||||||
|
key: botKey
|
||||||
|
}),
|
||||||
|
secretComment:
|
||||||
|
el.secretCommentTag && el.secretCommentIV && el.secretCommentCiphertext
|
||||||
|
? decryptSymmetric128BitHexKeyUTF8({
|
||||||
|
ciphertext: el.secretCommentCiphertext,
|
||||||
|
iv: el.secretCommentIV,
|
||||||
|
tag: el.secretCommentTag,
|
||||||
|
key: botKey
|
||||||
|
})
|
||||||
|
: ""
|
||||||
|
};
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullFolderPath = await getFullFolderPath({
|
|
||||||
folderDAL,
|
|
||||||
folderId: snapshotDetails.folderId,
|
|
||||||
envId: snapshotDetails.environment.id
|
|
||||||
});
|
|
||||||
|
|
||||||
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionSecretActions.ReadValue,
|
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
|
||||||
environment: snapshotDetails.environment.slug,
|
|
||||||
secretPath: fullFolderPath
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return snapshotDetails;
|
return snapshotDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable react/no-danger */
|
/* eslint-disable react/no-danger */
|
||||||
import { forwardRef, TextareaHTMLAttributes } from "react";
|
import { forwardRef, TextareaHTMLAttributes } from "react";
|
||||||
|
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import { useToggle } from "@app/hooks";
|
import { useToggle } from "@app/hooks";
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ export const decryptSecrets = (
|
|||||||
id: encSecret.id,
|
id: encSecret.id,
|
||||||
env: encSecret.environment,
|
env: encSecret.environment,
|
||||||
key: secretKey,
|
key: secretKey,
|
||||||
|
secretValueHidden: encSecret.secretValueHidden,
|
||||||
value: secretValue,
|
value: secretValue,
|
||||||
tags: encSecret.tags,
|
tags: encSecret.tags,
|
||||||
comment: secretComment,
|
comment: secretComment,
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export const useGetSnapshotSecrets = ({ snapshotId }: TSnapshotDataProps) =>
|
|||||||
id: secretVersion.secretId,
|
id: secretVersion.secretId,
|
||||||
env: data.environment.slug,
|
env: data.environment.slug,
|
||||||
key: secretVersion.secretKey,
|
key: secretVersion.secretKey,
|
||||||
|
secretValueHidden: false,
|
||||||
value: secretVersion.secretValue || "",
|
value: secretVersion.secretValue || "",
|
||||||
tags: secretVersion.tags,
|
tags: secretVersion.tags,
|
||||||
comment: secretVersion.secretComment,
|
comment: secretVersion.secretComment,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export type EncryptedSecret = {
|
|||||||
secretValueCiphertext: string;
|
secretValueCiphertext: string;
|
||||||
secretValueIV: string;
|
secretValueIV: string;
|
||||||
secretValueTag: string;
|
secretValueTag: string;
|
||||||
|
secretValueHidden: boolean;
|
||||||
__v: number;
|
__v: number;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ import {
|
|||||||
import { getKeyValue } from "@app/helpers/parseEnvVar";
|
import { getKeyValue } from "@app/helpers/parseEnvVar";
|
||||||
import { useCreateFolder, useCreateSecretV3, useCreateWsTag, useGetWsTags } from "@app/hooks/api";
|
import { useCreateFolder, useCreateSecretV3, useCreateWsTag, useGetWsTags } from "@app/hooks/api";
|
||||||
import { SecretType } from "@app/hooks/api/types";
|
import { SecretType } from "@app/hooks/api/types";
|
||||||
|
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||||
|
|
||||||
const typeSchema = z
|
const typeSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -275,7 +276,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
|
|||||||
isMulti
|
isMulti
|
||||||
options={environments.filter((environment) =>
|
options={environments.filter((environment) =>
|
||||||
permission.can(
|
permission.can(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionSecretActions.Create,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
environment: environment.slug,
|
environment: environment.slug,
|
||||||
secretPath,
|
secretPath,
|
||||||
|
|||||||
+4
-8
@@ -10,12 +10,8 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { IconButton, Input, Spinner, Tooltip } from "@app/components/v2";
|
import { IconButton, Input, Spinner, Tooltip } from "@app/components/v2";
|
||||||
import {
|
import { ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context";
|
||||||
ProjectPermissionActions,
|
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||||
ProjectPermissionSub,
|
|
||||||
useProjectPermission,
|
|
||||||
useWorkspace
|
|
||||||
} from "@app/context";
|
|
||||||
import { useToggle } from "@app/hooks";
|
import { useToggle } from "@app/hooks";
|
||||||
import { useUpdateSecretV3 } from "@app/hooks/api";
|
import { useUpdateSecretV3 } from "@app/hooks/api";
|
||||||
import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types";
|
import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types";
|
||||||
@@ -55,8 +51,8 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }
|
|||||||
secretTags: (secretDetails?.tags || []).map((i) => i.slug)
|
secretTags: (secretDetails?.tags || []).map((i) => i.slug)
|
||||||
});
|
});
|
||||||
const isSecretInEnvReadOnly =
|
const isSecretInEnvReadOnly =
|
||||||
permission.can(ProjectPermissionActions.Read, secretPermissionSubject) &&
|
permission.can(ProjectPermissionSecretActions.DescribeSecret, secretPermissionSubject) &&
|
||||||
permission.cannot(ProjectPermissionActions.Edit, secretPermissionSubject);
|
permission.cannot(ProjectPermissionSecretActions.Edit, secretPermissionSubject);
|
||||||
if (isSecretInEnvReadOnly) {
|
if (isSecretInEnvReadOnly) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -11,6 +11,7 @@ import {
|
|||||||
useProjectPermission,
|
useProjectPermission,
|
||||||
useWorkspace
|
useWorkspace
|
||||||
} from "@app/context";
|
} from "@app/context";
|
||||||
|
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import { useDeleteFolder, useDeleteSecretBatch } from "@app/hooks/api";
|
import { useDeleteFolder, useDeleteSecretBatch } from "@app/hooks/api";
|
||||||
import {
|
import {
|
||||||
@@ -58,7 +59,7 @@ export const SelectionPanel = ({ secretPath, resetSelectedEntries, selectedEntri
|
|||||||
// user should have the ability to delete secrets/folders in at least one of the envs
|
// user should have the ability to delete secrets/folders in at least one of the envs
|
||||||
const shouldShowDelete = userAvailableEnvs.some((env) =>
|
const shouldShowDelete = userAvailableEnvs.some((env) =>
|
||||||
permission.can(
|
permission.can(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionSecretActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
environment: env.slug,
|
environment: env.slug,
|
||||||
secretPath,
|
secretPath,
|
||||||
@@ -110,7 +111,7 @@ export const SelectionPanel = ({ secretPath, resetSelectedEntries, selectedEntri
|
|||||||
(accum: TDeleteSecretBatchDTO["secrets"], secretRecord) => {
|
(accum: TDeleteSecretBatchDTO["secrets"], secretRecord) => {
|
||||||
const entry = secretRecord[env.slug];
|
const entry = secretRecord[env.slug];
|
||||||
const canDeleteSecret = permission.can(
|
const canDeleteSecret = permission.can(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionSecretActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
environment: env.slug,
|
environment: env.slug,
|
||||||
secretPath,
|
secretPath,
|
||||||
|
|||||||
+3
-2
@@ -25,7 +25,8 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
Switch
|
Switch
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context";
|
import { ProjectPermissionSub, useProjectPermission } from "@app/context";
|
||||||
|
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||||
import { useDebounce } from "@app/hooks";
|
import { useDebounce } from "@app/hooks";
|
||||||
import { useMoveSecrets } from "@app/hooks/api";
|
import { useMoveSecrets } from "@app/hooks/api";
|
||||||
import { useGetProjectSecretsQuickSearch } from "@app/hooks/api/dashboard";
|
import { useGetProjectSecretsQuickSearch } from "@app/hooks/api/dashboard";
|
||||||
@@ -95,7 +96,7 @@ const Content = ({
|
|||||||
env.slug,
|
env.slug,
|
||||||
{
|
{
|
||||||
missingPermissions: permission.cannot(
|
missingPermissions: permission.cannot(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionSecretActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
environment: env.slug,
|
environment: env.slug,
|
||||||
secretPath: sourceSecretPath,
|
secretPath: sourceSecretPath,
|
||||||
|
|||||||
@@ -122,8 +122,6 @@ const Page = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Can read secret value", canReadSecret);
|
|
||||||
|
|
||||||
const canReadSecretImports = permission.can(
|
const canReadSecretImports = permission.can(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.SecretImports, { environment, secretPath })
|
subject(ProjectPermissionSub.SecretImports, { environment, secretPath })
|
||||||
|
|||||||
Reference in New Issue
Block a user