mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 04:26:33 +00:00
fix: hidden secret value in secret approvals
This commit is contained in:
@@ -285,6 +285,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
commits: secretRawSchema
|
commits: secretRawSchema
|
||||||
.omit({ _id: true, environment: true, workspace: true, type: true, version: true, secretValue: true })
|
.omit({ _id: true, environment: true, workspace: true, type: true, version: true, secretValue: true })
|
||||||
.extend({
|
.extend({
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
isRotatedSecret: z.boolean().optional(),
|
isRotatedSecret: z.boolean().optional(),
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
@@ -296,6 +297,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
version: z.number(),
|
version: z.number(),
|
||||||
secretKey: z.string(),
|
secretKey: z.string(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretComment: z.string().optional()
|
secretComment: z.string().optional()
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
@@ -306,6 +308,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
version: z.number(),
|
version: z.number(),
|
||||||
secretKey: z.string(),
|
secretKey: z.string(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretComment: z.string().optional(),
|
secretComment: z.string().optional(),
|
||||||
tags: SanitizedTagSchema.array().optional(),
|
tags: SanitizedTagSchema.array().optional(),
|
||||||
secretMetadata: ResourceMetadataSchema.nullish()
|
secretMetadata: ResourceMetadataSchema.nullish()
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ import {
|
|||||||
fnSecretBulkDelete,
|
fnSecretBulkDelete,
|
||||||
fnSecretBulkInsert,
|
fnSecretBulkInsert,
|
||||||
fnSecretBulkUpdate,
|
fnSecretBulkUpdate,
|
||||||
getAllNestedSecretReferences
|
getAllNestedSecretReferences,
|
||||||
|
INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
} from "@app/services/secret/secret-fns";
|
} from "@app/services/secret/secret-fns";
|
||||||
import { TSecretQueueFactory } from "@app/services/secret/secret-queue";
|
import { TSecretQueueFactory } from "@app/services/secret/secret-queue";
|
||||||
import { SecretOperations } from "@app/services/secret/secret-types";
|
import { SecretOperations } from "@app/services/secret/secret-types";
|
||||||
@@ -267,7 +268,6 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
ProjectPermissionSecretActions.DescribeAndReadValue,
|
ProjectPermissionSecretActions.DescribeAndReadValue,
|
||||||
ProjectPermissionSub.Secrets
|
ProjectPermissionSub.Secrets
|
||||||
);
|
);
|
||||||
const hiddenSecretValue = "******";
|
|
||||||
|
|
||||||
let secrets;
|
let secrets;
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
@@ -285,8 +285,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
version: el.version,
|
version: el.version,
|
||||||
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
||||||
isRotatedSecret: el.secret?.isRotatedSecret ?? false,
|
isRotatedSecret: el.secret?.isRotatedSecret ?? false,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secret && el.secret.isRotatedSecret
|
: el.secret && el.secret.isRotatedSecret
|
||||||
? undefined
|
? undefined
|
||||||
: el.encryptedValue
|
: el.encryptedValue
|
||||||
@@ -300,8 +301,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.secret.key,
|
secretKey: el.secret.key,
|
||||||
id: el.secret.id,
|
id: el.secret.id,
|
||||||
version: el.secret.version,
|
version: el.secret.version,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secret.encryptedValue
|
: el.secret.encryptedValue
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.secret.encryptedValue }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.secret.encryptedValue }).toString()
|
||||||
: "",
|
: "",
|
||||||
@@ -315,8 +317,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.secretVersion.key,
|
secretKey: el.secretVersion.key,
|
||||||
id: el.secretVersion.id,
|
id: el.secretVersion.id,
|
||||||
version: el.secretVersion.version,
|
version: el.secretVersion.version,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secretVersion.encryptedValue
|
: el.secretVersion.encryptedValue
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedValue }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedValue }).toString()
|
||||||
: "",
|
: "",
|
||||||
@@ -333,11 +336,13 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
const encryptedSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id);
|
const encryptedSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id);
|
||||||
secrets = encryptedSecrets.map((el) => ({
|
secrets = encryptedSecrets.map((el) => ({
|
||||||
...el,
|
...el,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
...decryptSecretWithBot(el, botKey),
|
...decryptSecretWithBot(el, botKey),
|
||||||
secret: el.secret
|
secret: el.secret
|
||||||
? {
|
? {
|
||||||
id: el.secret.id,
|
id: el.secret.id,
|
||||||
version: el.secret.version,
|
version: el.secret.version,
|
||||||
|
secretValueHidden: false,
|
||||||
...decryptSecretWithBot(el.secret, botKey)
|
...decryptSecretWithBot(el.secret, botKey)
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -345,6 +350,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
? {
|
? {
|
||||||
id: el.secretVersion.id,
|
id: el.secretVersion.id,
|
||||||
version: el.secretVersion.version,
|
version: el.secretVersion.version,
|
||||||
|
secretValueHidden: false,
|
||||||
...decryptSecretWithBot(el.secretVersion, botKey)
|
...decryptSecretWithBot(el.secretVersion, botKey)
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
@@ -353,6 +359,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
const secretPath = await folderDAL.findSecretPathByFolderIds(secretApprovalRequest.projectId, [
|
const secretPath = await folderDAL.findSecretPathByFolderIds(secretApprovalRequest.projectId, [
|
||||||
secretApprovalRequest.folderId
|
secretApprovalRequest.folderId
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
|
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const syntaxHighlight = (content?: string | null, isVisible?: boolean, isImport?
|
|||||||
type Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
type Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
||||||
value?: string | null;
|
value?: string | null;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
|
valueAlwaysHidden?: boolean;
|
||||||
isImport?: boolean;
|
isImport?: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
@@ -63,6 +64,7 @@ export const SecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
|||||||
value,
|
value,
|
||||||
isVisible,
|
isVisible,
|
||||||
isImport,
|
isImport,
|
||||||
|
valueAlwaysHidden,
|
||||||
containerClassName,
|
containerClassName,
|
||||||
onBlur,
|
onBlur,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
@@ -84,7 +86,11 @@ export const SecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
|||||||
<pre aria-hidden className="m-0">
|
<pre aria-hidden className="m-0">
|
||||||
<code className={`inline-block w-full ${commonClassName}`}>
|
<code className={`inline-block w-full ${commonClassName}`}>
|
||||||
<span style={{ whiteSpace: "break-spaces" }}>
|
<span style={{ whiteSpace: "break-spaces" }}>
|
||||||
{syntaxHighlight(value, isVisible || isSecretFocused, isImport)}
|
{syntaxHighlight(
|
||||||
|
value,
|
||||||
|
isVisible || (isSecretFocused && !valueAlwaysHidden),
|
||||||
|
isImport
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export type TSecretApprovalSecChange = {
|
|||||||
version: number;
|
version: number;
|
||||||
secretKey: string;
|
secretKey: string;
|
||||||
secretValue?: string;
|
secretValue?: string;
|
||||||
|
secretValueHidden?: boolean;
|
||||||
secretComment?: string;
|
secretComment?: string;
|
||||||
isRotatedSecret?: boolean;
|
isRotatedSecret?: boolean;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
|
|||||||
+55
-20
@@ -14,6 +14,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
|
|
||||||
import { SecretInput, Tag, Tooltip } from "@app/components/v2";
|
import { SecretInput, Tag, Tooltip } from "@app/components/v2";
|
||||||
import { CommitType, SecretV3Raw, TSecretApprovalSecChange, WsTag } from "@app/hooks/api/types";
|
import { CommitType, SecretV3Raw, TSecretApprovalSecChange, WsTag } from "@app/hooks/api/types";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
op: CommitType;
|
op: CommitType;
|
||||||
@@ -105,21 +106,38 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
{secretVersion?.secretValueHidden && (
|
||||||
|
<div className="absolute left-1 top-1/2 -translate-y-1/2">
|
||||||
|
<Tooltip content="You do not have access to view the old secret value.">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
className="pl-2 text-mineshaft-300"
|
||||||
|
size="sm"
|
||||||
|
icon={faEyeSlash}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<SecretInput
|
<SecretInput
|
||||||
isReadOnly
|
isReadOnly
|
||||||
isVisible={isOldSecretValueVisible}
|
isVisible={isOldSecretValueVisible}
|
||||||
|
valueAlwaysHidden={secretVersion?.secretValueHidden}
|
||||||
value={secretVersion?.secretValue}
|
value={secretVersion?.secretValue}
|
||||||
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-700 px-2 py-1.5"
|
containerClassName={twMerge(
|
||||||
|
"border border-mineshaft-600 bg-bunker-700 py-1.5 text-bunker-300 hover:border-primary-400/50",
|
||||||
|
secretVersion?.secretValueHidden ? "pl-8 pr-2" : "px-2"
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<div
|
{!secretVersion?.secretValueHidden && (
|
||||||
className="absolute right-1 top-1"
|
<div
|
||||||
onClick={() => setIsOldSecretValueVisible(!isOldSecretValueVisible)}
|
className="absolute right-1 top-1"
|
||||||
>
|
onClick={() => setIsOldSecretValueVisible(!isOldSecretValueVisible)}
|
||||||
<FontAwesomeIcon
|
>
|
||||||
icon={isOldSecretValueVisible ? faEyeSlash : faEye}
|
<FontAwesomeIcon
|
||||||
className="cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-800 p-1.5 text-mineshaft-300 hover:bg-mineshaft-700"
|
icon={isOldSecretValueVisible ? faEyeSlash : faEye}
|
||||||
/>
|
className="cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-800 p-1.5 text-mineshaft-300 hover:bg-mineshaft-700"
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -211,21 +229,38 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
{newVersion?.secretValueHidden && (
|
||||||
|
<div className="absolute left-1 top-1/2 -translate-y-1/2">
|
||||||
|
<Tooltip content="You do not have access to view the new secret value.">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
className="pl-2 text-mineshaft-300"
|
||||||
|
size="sm"
|
||||||
|
icon={faEyeSlash}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<SecretInput
|
<SecretInput
|
||||||
isReadOnly
|
isReadOnly
|
||||||
|
valueAlwaysHidden={newVersion?.secretValueHidden}
|
||||||
isVisible={isNewSecretValueVisible}
|
isVisible={isNewSecretValueVisible}
|
||||||
value={newVersion?.secretValue}
|
value={newVersion?.secretValue}
|
||||||
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-700 px-2 py-1.5"
|
containerClassName={twMerge(
|
||||||
|
"border border-mineshaft-600 bg-bunker-700 py-1.5 text-bunker-300 hover:border-primary-400/50",
|
||||||
|
newVersion?.secretValueHidden ? "pl-8 pr-2" : "px-2"
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<div
|
{!newVersion?.secretValueHidden && (
|
||||||
className="absolute right-1 top-1"
|
<div
|
||||||
onClick={() => setIsNewSecretValueVisible(!isNewSecretValueVisible)}
|
className="absolute right-1 top-1"
|
||||||
>
|
onClick={() => setIsNewSecretValueVisible(!isNewSecretValueVisible)}
|
||||||
<FontAwesomeIcon
|
>
|
||||||
icon={isNewSecretValueVisible ? faEyeSlash : faEye}
|
<FontAwesomeIcon
|
||||||
className="cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-800 p-1.5 text-mineshaft-300 hover:bg-mineshaft-700"
|
icon={isNewSecretValueVisible ? faEyeSlash : faEye}
|
||||||
/>
|
className="cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-800 p-1.5 text-mineshaft-300 hover:bg-mineshaft-700"
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user