From b7b0e60b1d6eef6c571e48527d3d47069358cafc Mon Sep 17 00:00:00 2001 From: = Date: Tue, 23 Jul 2024 00:55:18 +0530 Subject: [PATCH] feat: ui removed all private key except secret rotation to raw endpoints version --- .../api/secretApprovalRequest/queries.tsx | 60 +------------------ .../hooks/api/secretApprovalRequest/types.ts | 22 +++---- .../src/hooks/api/secretSnapshots/queries.tsx | 60 ++++++------------- .../src/hooks/api/secretSnapshots/types.ts | 6 +- frontend/src/hooks/api/secrets/queries.tsx | 39 ++---------- frontend/src/hooks/api/secrets/types.ts | 13 ++-- .../SecretApprovalRequestChangeItem.tsx | 27 +++++---- .../SecretApprovalRequestChanges.tsx | 7 ++- .../views/SecretMainPage/SecretMainPage.tsx | 7 --- .../SecretListView/SecretDetaiSidebar.tsx | 11 ++-- .../SecretListView/SecretListView.tsx | 7 +-- .../components/SnapshotView/SnapshotView.tsx | 7 +-- 12 files changed, 66 insertions(+), 200 deletions(-) diff --git a/frontend/src/hooks/api/secretApprovalRequest/queries.tsx b/frontend/src/hooks/api/secretApprovalRequest/queries.tsx index 68db377cf..d990797b6 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/queries.tsx +++ b/frontend/src/hooks/api/secretApprovalRequest/queries.tsx @@ -13,15 +13,13 @@ import { import { apiRequest } from "@app/config/request"; import { UserWsKeyPair } from "../keys/types"; -import { EncryptedSecret, SecretType,SecretV3RawSanitized } from "../secrets/types"; +import { EncryptedSecret, SecretType, SecretV3RawSanitized } from "../secrets/types"; import { - CommitType, TGetSecretApprovalRequestCount, TGetSecretApprovalRequestDetails, TGetSecretApprovalRequestList, TSecretApprovalRequest, - TSecretApprovalRequestCount, - TSecretApprovalSecChangeData + TSecretApprovalRequestCount } from "./types"; export const secretApprovalRequestKeys = { @@ -117,48 +115,6 @@ export const decryptSecrets = ( return secrets; }; -export const decryptSecretApprovalSecret = ( - encSecret: TSecretApprovalSecChangeData, - decryptFileKey: UserWsKeyPair -) => { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; - const key = decryptAssymmetric({ - ciphertext: decryptFileKey.encryptedKey, - nonce: decryptFileKey.nonce, - publicKey: decryptFileKey.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - 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, - version: encSecret.version, - secretKey, - secretValue, - secretComment, - tags: encSecret.tags - }; -}; - const fetchSecretApprovalRequestList = async ({ workspaceId, environment, @@ -245,7 +201,7 @@ export const useGetSecretApprovalRequestDetails = ({ UseQueryOptions< TSecretApprovalRequest, unknown, - TSecretApprovalRequest, + TSecretApprovalRequest, ReturnType >, "queryKey" | "queryFn" @@ -254,16 +210,6 @@ export const useGetSecretApprovalRequestDetails = ({ useQuery({ queryKey: secretApprovalRequestKeys.detail({ id }), queryFn: () => fetchSecretApprovalRequestDetails({ id }), - select: (data) => ({ - ...data, - commits: data.commits.map(({ secretVersion, op, secret, ...newVersion }) => ({ - op, - secret, - secretVersion: secretVersion ? decryptSecrets([secretVersion], decryptKey)[0] : undefined, - newVersion: - op !== CommitType.DELETE ? decryptSecretApprovalSecret(newVersion, decryptKey) : undefined - })) - }), enabled: Boolean(id && decryptKey) && (options?.enabled ?? true) }); diff --git a/frontend/src/hooks/api/secretApprovalRequest/types.ts b/frontend/src/hooks/api/secretApprovalRequest/types.ts index ba7cbc38d..9d9e46a7f 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/types.ts +++ b/frontend/src/hooks/api/secretApprovalRequest/types.ts @@ -1,6 +1,6 @@ import { UserWsKeyPair } from "../keys/types"; import { TSecretApprovalPolicy } from "../secretApproval/types"; -import { EncryptedSecret } from "../secrets/types"; +import { SecretV3Raw } from "../secrets/types"; import { WsTag } from "../tags/types"; export enum ApprovalStatus { @@ -17,15 +17,9 @@ export enum CommitType { export type TSecretApprovalSecChangeData = { id: string; - secretKeyCiphertext: string; - secretKeyIV: string; - secretKeyTag: string; - secretValueCiphertext: string; - secretValueIV: string; - secretValueTag: string; - secretCommentIV: string; - secretCommentTag: string; - secretCommentCiphertext: string; + secretKey: string; + secretValue?: string; + secretComment?: string; skipMultilineEncoding?: boolean; algorithm: "aes-256-gcm"; keyEncoding: "utf8" | "base64"; @@ -37,12 +31,12 @@ export type TSecretApprovalSecChange = { id: string; version: number; secretKey: string; - secretValue: string; - secretComment: string; + secretValue?: string; + secretComment?: string; tags?: string[]; }; -export type TSecretApprovalRequest = { +export type TSecretApprovalRequest = { id: string; isReplicated?: boolean; slug: string; @@ -90,7 +84,7 @@ export type TSecretApprovalRequest = { commits: ({ // if there is no secret means it was creation secret?: { version: number }; - secretVersion: J; + secretVersion: SecretV3Raw; // if there is no new version its for Delete op: CommitType; } & TSecretApprovalSecChangeData)[]; diff --git a/frontend/src/hooks/api/secretSnapshots/queries.tsx b/frontend/src/hooks/api/secretSnapshots/queries.tsx index 7709d3785..f45d6db5e 100644 --- a/frontend/src/hooks/api/secretSnapshots/queries.tsx +++ b/frontend/src/hooks/api/secretSnapshots/queries.tsx @@ -1,13 +1,9 @@ /* eslint-disable no-param-reassign */ import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { - decryptAssymmetric, - decryptSymmetric -} from "@app/components/utilities/cryptography/crypto"; import { apiRequest } from "@app/config/request"; -import { SecretType,SecretV3RawSanitized } from "../secrets/types"; +import { SecretType, SecretV3RawSanitized } from "../secrets/types"; import { TGetSecretSnapshotsDTO, TSecretRollbackDTO, @@ -65,55 +61,33 @@ const fetchSnapshotEncSecrets = async (snapshotId: string) => { return res.data.secretSnapshot; }; -export const useGetSnapshotSecrets = ({ decryptFileKey, snapshotId }: TSnapshotDataProps) => +export const useGetSnapshotSecrets = ({ snapshotId }: TSnapshotDataProps) => useQuery({ queryKey: secretSnapshotKeys.snapshotData(snapshotId), - enabled: Boolean(snapshotId && decryptFileKey), + enabled: Boolean(snapshotId), queryFn: () => fetchSnapshotEncSecrets(snapshotId), select: (data) => { - 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 - }); - const sharedSecrets: SecretV3RawSanitized[] = []; const personalSecrets: Record = {}; - data.secretVersions.forEach((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 = ""; - + data.secretVersions.forEach((secretVersion) => { const decryptedSecret = { - id: encSecret.secretId, + id: secretVersion.secretId, env: data.environment.slug, - key: secretKey, - value: secretValue, - tags: encSecret.tags, - comment: secretComment, - createdAt: encSecret.createdAt, - updatedAt: encSecret.updatedAt, + key: secretVersion.secretKey, + value: secretVersion.secretValue || "", + tags: secretVersion.tags, + comment: secretVersion.secretComment, + createdAt: secretVersion.createdAt, + updatedAt: secretVersion.updatedAt, type: "modified", - version: encSecret.version + version: secretVersion.version }; - if (encSecret.type === SecretType.Personal) { - personalSecrets[decryptedSecret.key] = { id: encSecret.secretId, value: secretValue }; + if (secretVersion.type === SecretType.Personal) { + personalSecrets[decryptedSecret.key] = { + id: secretVersion.secretId, + value: secretVersion.secretValue || "" + }; } else { sharedSecrets.push(decryptedSecret); } diff --git a/frontend/src/hooks/api/secretSnapshots/types.ts b/frontend/src/hooks/api/secretSnapshots/types.ts index 2eb956a8a..54bf152cc 100644 --- a/frontend/src/hooks/api/secretSnapshots/types.ts +++ b/frontend/src/hooks/api/secretSnapshots/types.ts @@ -1,5 +1,4 @@ -import { UserWsKeyPair } from "../keys/types"; -import { EncryptedSecretVersion } from "../secrets/types"; +import { SecretVersions } from "../secrets/types"; import { WorkspaceEnv } from "../types"; export type TSecretSnapshot = { @@ -12,7 +11,7 @@ export type TSecretSnapshot = { export type TSnapshotData = Omit & { id: string; - secretVersions: EncryptedSecretVersion[]; + secretVersions: SecretVersions[]; folderVersion: Array<{ name: string; id: string }>; environment: WorkspaceEnv; }; @@ -20,7 +19,6 @@ export type TSnapshotData = Omit & { export type TSnapshotDataProps = { snapshotId: string; env: string; - decryptFileKey: UserWsKeyPair; }; export type TGetSecretSnapshotsDTO = { diff --git a/frontend/src/hooks/api/secrets/queries.tsx b/frontend/src/hooks/api/secrets/queries.tsx index 5864102d8..1ad710db4 100644 --- a/frontend/src/hooks/api/secrets/queries.tsx +++ b/frontend/src/hooks/api/secrets/queries.tsx @@ -2,19 +2,15 @@ import { useCallback, useMemo } 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 { - EncryptedSecretVersion, GetSecretVersionsDTO, SecretType, SecretV3Raw, SecretV3RawResponse, SecretV3RawSanitized, + SecretVersions, TGetProjectSecretsAllEnvDTO, TGetProjectSecretsDTO, TGetProjectSecretsKey @@ -166,7 +162,7 @@ export const useGetProjectSecretsAllEnv = ({ }; const fetchEncryptedSecretVersion = async (secretId: string, offset: number, limit: number) => { - const { data } = await apiRequest.get<{ secretVersions: EncryptedSecretVersion[] }>( + const { data } = await apiRequest.get<{ secretVersions: SecretVersions[] }>( `/api/v1/secret/${secretId}/secret-versions`, { params: { @@ -180,33 +176,10 @@ const fetchEncryptedSecretVersion = async (secretId: string, offset: number, lim export const useGetSecretVersion = (dto: GetSecretVersionsDTO) => useQuery({ - enabled: Boolean(dto.secretId && dto.decryptFileKey), + enabled: Boolean(dto.secretId), queryKey: secretKeys.getSecretVersion(dto.secretId), queryFn: () => fetchEncryptedSecretVersion(dto.secretId, dto.offset, dto.limit), - select: useCallback( - (data: EncryptedSecretVersion[]) => { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; - const latestKey = dto.decryptFileKey; - const key = decryptAssymmetric({ - ciphertext: latestKey.encryptedKey, - nonce: latestKey.nonce, - publicKey: latestKey.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - return data - .map((el) => ({ - createdAt: el.createdAt, - id: el.id, - value: decryptSymmetric({ - ciphertext: el.secretValueCiphertext, - iv: el.secretValueIV, - tag: el.secretValueTag, - key - }) - })) - .sort((a, b) => b.createdAt.localeCompare(a.createdAt)); - }, - [dto.decryptFileKey] - ) + select: useCallback((data: SecretVersions[]) => { + return data.sort((a, b) => b.createdAt.localeCompare(a.createdAt)); + }, []) }); diff --git a/frontend/src/hooks/api/secrets/types.ts b/frontend/src/hooks/api/secrets/types.ts index d82e2203b..fbc67b92e 100644 --- a/frontend/src/hooks/api/secrets/types.ts +++ b/frontend/src/hooks/api/secrets/types.ts @@ -1,4 +1,3 @@ -import type { UserWsKeyPair } from "../keys/types"; import type { WsTag } from "../tags/types"; export enum SecretType { @@ -79,7 +78,7 @@ export type SecretV3RawResponse = { }[]; }; -export type EncryptedSecretVersion = { +export type SecretVersions = { id: string; secretId: string; version: number; @@ -87,12 +86,9 @@ export type EncryptedSecretVersion = { type: SecretType; isDeleted: boolean; envId: string; - secretKeyCiphertext: string; - secretKeyIV: string; - secretKeyTag: string; - secretValueCiphertext: string; - secretValueIV: string; - secretValueTag: string; + secretKey: string; + secretValue?: string; + secretComment?: string; tags: WsTag[]; __v: number; skipMultilineEncoding?: boolean; @@ -123,7 +119,6 @@ export type GetSecretVersionsDTO = { secretId: string; limit: number; offset: number; - decryptFileKey: UserWsKeyPair; }; export type TCreateSecretsV3DTO = { diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx index 0b6e9ac10..3fbe4357b 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx @@ -13,16 +13,11 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { - CommitType, - SecretV3RawSanitized, - TSecretApprovalSecChange, - WsTag -} from "@app/hooks/api/types"; +import { CommitType, SecretV3Raw, TSecretApprovalSecChange, WsTag } from "@app/hooks/api/types"; export type Props = { op: CommitType; - secretVersion?: SecretV3RawSanitized; + secretVersion?: SecretV3Raw; newVersion?: Omit & { tags?: WsTag[] }; presentSecretVersionNumber: number; hasMerged?: Boolean; @@ -96,11 +91,11 @@ export const SecretApprovalRequestChangeItem = ({ OLD - {secretVersion?.key} + {secretVersion?.secretKey} - + - {secretVersion?.comment} + {secretVersion?.secretComment} {secretVersion?.tags?.map(({ name, id: tagId, color }) => ( - {op === CommitType.CREATE ? newVersion?.secretKey : secretVersion?.key} + + {op === CommitType.CREATE ? newVersion?.secretKey : secretVersion?.secretKey} + - {op === CommitType.CREATE ? newVersion?.secretComment : secretVersion?.comment} + {op === CommitType.CREATE + ? newVersion?.secretComment + : secretVersion?.secretComment} {(op === CommitType.CREATE ? newVersion?.tags : secretVersion?.tags)?.map( diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx index 7e8e30483..45de6417c 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx @@ -230,7 +230,7 @@ export const SecretApprovalRequestChanges = ({
{secretApprovalRequestDetails.commits.map( - ({ op, secretVersion, secret, newVersion }, index) => ( + ({ op, secretVersion, secret, ...newVersion }, index) => (
{requiredApprover?.email} diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.tsx index b9258225f..8a7a21bbe 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.tsx @@ -23,13 +23,11 @@ import { useGetProjectSecrets, useGetSecretApprovalPolicyOfABoard, useGetSecretImports, - useGetUserWsKey, useGetWorkspaceSnapshotList, useGetWsSnapshotCount, useGetWsTags } from "@app/hooks/api"; -import { ProjectIndexSecretsSection } from "../SecretOverviewPage/components/ProjectIndexSecretsSection"; import { ActionBar } from "./components/ActionBar"; import { CreateSecretForm } from "./components/CreateSecretForm"; import { DynamicSecretListView } from "./components/DynamicSecretListView"; @@ -93,8 +91,6 @@ export const SecretMainPage = () => { } }, [isWorkspaceLoading, currentWorkspace, environment, router.isReady]); - const { data: decryptFileKey } = useGetUserWsKey(workspaceId); - // fetch secrets const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({ environment, @@ -248,7 +244,6 @@ export const SecretMainPage = () => { protectionPolicyName={boardPolicy?.name} />
- {!isRollbackMode ? ( <> { environment={environment} workspaceId={workspaceId} secretPath={secretPath} - decryptFileKey={decryptFileKey!} isProtectedBranch={isProtectedBranch} /> )} @@ -367,7 +361,6 @@ export const SecretMainPage = () => { ) : ( void; onClose: () => void; secret: SecretV3RawSanitized; - decryptFileKey: UserWsKeyPair; onDeleteSecret: () => void; onSaveSecret: ( orgSec: SecretV3RawSanitized, @@ -64,7 +63,6 @@ type Props = { export const SecretDetailSidebar = ({ isOpen, onToggle, - decryptFileKey, secret, onDeleteSecret, onSaveSecret, @@ -114,8 +112,7 @@ export const SecretDetailSidebar = ({ const { data: secretVersion } = useGetSecretVersion({ limit: 10, offset: 0, - secretId: secret?.id, - decryptFileKey + secretId: secret?.id }); const handleOverrideClick = () => { @@ -428,7 +425,7 @@ export const SecretDetailSidebar = ({
Version History
- {secretVersion?.map(({ createdAt, value, id }, i) => ( + {secretVersion?.map(({ createdAt, secretValue, id }, i) => (
@@ -438,7 +435,7 @@ export const SecretDetailSidebar = ({
Value:
-
{value}
+
{secretValue}
))} diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx index b3f0fb890..a9597e214 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx @@ -10,9 +10,9 @@ import { usePopUp } from "@app/hooks"; import { useCreateSecretV3, useDeleteSecretV3, useUpdateSecretV3 } from "@app/hooks/api"; import { secretApprovalRequestKeys } from "@app/hooks/api/secretApprovalRequest/queries"; import { secretKeys } from "@app/hooks/api/secrets/queries"; -import { SecretType,SecretV3RawSanitized } from "@app/hooks/api/secrets/types"; +import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/secrets/types"; import { secretSnapshotKeys } from "@app/hooks/api/secretSnapshots/queries"; -import { UserWsKeyPair, WsTag } from "@app/hooks/api/types"; +import { WsTag } from "@app/hooks/api/types"; import { AddShareSecretModal } from "@app/views/ShareSecretPage/components/AddShareSecretModal"; import { useSelectedSecretActions, useSelectedSecrets } from "../../SecretMainPage.store"; @@ -25,7 +25,6 @@ type Props = { secrets?: SecretV3RawSanitized[]; environment: string; workspaceId: string; - decryptFileKey: UserWsKeyPair; secretPath?: string; filter: Filter; sortDir?: SortDir; @@ -88,7 +87,6 @@ export const SecretListView = ({ secrets = [], environment, workspaceId, - decryptFileKey, secretPath = "/", filter, sortDir = SortDir.ASC, @@ -392,7 +390,6 @@ export const SecretListView = ({ secretPath={secretPath} isOpen={popUp.secretDetail.isOpen} onToggle={(isOpen) => handlePopUpToggle("secretDetail", isOpen)} - decryptFileKey={decryptFileKey} secret={popUp.secretDetail.data as SecretV3RawSanitized} onDeleteSecret={() => handlePopUpOpen("deleteSecret", popUp.secretDetail.data)} onClose={() => handlePopUpClose("secretDetail")} diff --git a/frontend/src/views/SecretMainPage/components/SnapshotView/SnapshotView.tsx b/frontend/src/views/SecretMainPage/components/SnapshotView/SnapshotView.tsx index 734159382..8658c0da2 100644 --- a/frontend/src/views/SecretMainPage/components/SnapshotView/SnapshotView.tsx +++ b/frontend/src/views/SecretMainPage/components/SnapshotView/SnapshotView.tsx @@ -14,7 +14,7 @@ import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, ContentLoader, Input, Tag, Tooltip } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; import { useGetSnapshotSecrets, usePerformSecretRollback } from "@app/hooks/api"; -import { SecretV3RawSanitized, TSecretFolder, UserWsKeyPair } from "@app/hooks/api/types"; +import { SecretV3RawSanitized, TSecretFolder } from "@app/hooks/api/types"; import { renderIcon, SecretItem, TDiffModes, TDiffView } from "./SecretItem"; @@ -23,7 +23,6 @@ type Props = { environment: string; workspaceId: string; secretPath?: string; - decryptFileKey: UserWsKeyPair; secrets?: SecretV3RawSanitized[]; folders?: TSecretFolder[]; snapshotCount?: number; @@ -45,7 +44,6 @@ export const SnapshotView = ({ environment, workspaceId, secretPath, - decryptFileKey, secrets = [], folders = [], onGoBack, @@ -57,8 +55,7 @@ export const SnapshotView = ({ const { data: snapshotData, isLoading: isSnapshotLoading } = useGetSnapshotSecrets({ snapshotId, - env: environment, - decryptFileKey + env: environment }); const rollingFolder = snapshotData?.folders || [];