feat(secret-approval): implemented the base

This commit is contained in:
Akhil Mohan
2023-10-05 20:33:48 +05:30
parent a995627815
commit fc43511f5d
22 changed files with 1467 additions and 49 deletions
+1
View File
@@ -8,6 +8,7 @@ export * from "./keys";
export * from "./organization";
export * from "./roles";
export * from "./secretApproval";
export * from "./secretApprovalRequest";
export * from "./secretFolders";
export * from "./secretImports";
export * from "./secrets";
@@ -0,0 +1,2 @@
export { useUpdateSecretApprovalRequestStatus } from "./mutation";
export { useGetSecretApprovalRequestDetails, useGetSecretApprovalRequests } from "./queries";
@@ -0,0 +1,20 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { secretApprovalRequestKeys } from "./queries";
import { TUpdateSecretApprovalRequestStatusDTO } from "./types";
export const useUpdateSecretApprovalRequestStatus = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, TUpdateSecretApprovalRequestStatusDTO>({
mutationFn: async ({ id, status }) => {
const { data } = await apiRequest.post(`/api/v1/secret-approval-requests/${id}`, { status });
return data;
},
onSuccess: (_, { id }) => {
queryClient.invalidateQueries(secretApprovalRequestKeys.detail({ id }));
}
});
};
@@ -0,0 +1,144 @@
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import {
decryptAssymmetric,
decryptSymmetric
} from "@app/components/utilities/cryptography/crypto";
import { apiRequest } from "@app/config/request";
import { UserWsKeyPair } from "../keys/types";
import { decryptSecrets } from "../secrets/queries";
import { DecryptedSecret } from "../secrets/types";
import {
TGetSecretApprovalRequestDetails,
TGetSecretApprovalRequestList,
TSecretApprovalRequest,
TSecretApprovalSecChange,
TSecretApprovalSecChangeData
} from "./types";
export const secretApprovalRequestKeys = {
list: ({ workspaceId, environment }: TGetSecretApprovalRequestList) =>
[{ workspaceId, environment }, "secret-approval-requests"] as const,
detail: ({ id }: Omit<TGetSecretApprovalRequestDetails, "decryptKey">) =>
[{ id }, "secret-approval-request-detail"] as const
};
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
}: TGetSecretApprovalRequestList) => {
const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequest[] }>(
"/api/v1/secret-approval-requests",
{
params: {
workspaceId,
environment
}
}
);
return data.approvals;
};
export const useGetSecretApprovalRequests = ({
workspaceId,
environment,
options = {}
}: TGetSecretApprovalRequestList & {
options?: Omit<
UseQueryOptions<
TSecretApprovalRequest[],
unknown,
TSecretApprovalRequest[],
ReturnType<typeof secretApprovalRequestKeys.list>
>,
"queryKey" | "queryFn"
>;
}) =>
useQuery({
queryKey: secretApprovalRequestKeys.list({ workspaceId, environment }),
queryFn: () => fetchSecretApprovalRequestList({ workspaceId, environment }),
enabled: Boolean(workspaceId) && (options?.enabled ?? true)
});
const fetchSecretApprovalRequestDetails = async ({
id
}: Omit<TGetSecretApprovalRequestDetails, "decryptKey">) => {
const { data } = await apiRequest.get<{ approval: TSecretApprovalRequest }>(
`/api/v1/secret-approval-requests/${id}`
);
return data.approval;
};
export const useGetSecretApprovalRequestDetails = ({
id,
decryptKey,
options = {}
}: TGetSecretApprovalRequestDetails & {
options?: Omit<
UseQueryOptions<
TSecretApprovalRequest,
unknown,
TSecretApprovalRequest<TSecretApprovalSecChange, DecryptedSecret>,
ReturnType<typeof secretApprovalRequestKeys.detail>
>,
"queryKey" | "queryFn"
>;
}) =>
useQuery({
queryKey: secretApprovalRequestKeys.detail({ id }),
queryFn: () => fetchSecretApprovalRequestDetails({ id }),
select: (data) => ({
...data,
commits: data.commits.map(({ secret, op, newVersion }) => ({
op,
secret: secret ? decryptSecrets([secret], decryptKey)[0] : undefined,
newVersion: newVersion ? decryptSecretApprovalSecret(newVersion, decryptKey) : undefined
}))
}),
enabled: Boolean(id && decryptKey) && (options?.enabled ?? true)
});
@@ -0,0 +1,83 @@
import { UserWsKeyPair } from "../keys/types";
import { TSecretApprovalPolicy } from "../secretApproval/types";
import { EncryptedSecret } from "../secrets/types";
import { WsTag } from "../tags/types";
export enum ApprovalStatus {
PENDING = "pending",
APPROVED = "approved",
REJECTED = "rejected"
}
export enum CommitType {
DELETE = "delete",
UPDATE = "update",
CREATE = "create"
}
export type TSecretApprovalSecChangeData = {
_id: string;
version: number;
secretKeyCiphertext: string;
secretKeyIV: string;
secretKeyTag: string;
secretValueCiphertext: string;
secretValueIV: string;
secretValueTag: string;
secretCommentIV: string;
secretCommentTag: string;
secretCommentCiphertext: string;
skipMultilineEncoding?: boolean;
algorithm: "aes-256-gcm";
keyEncoding: "utf8" | "base64";
tags?: WsTag[];
};
export type TSecretApprovalSecChange = {
_id: string;
version: number;
secretKey: string;
secretValue: string;
secretComment: string;
tags?: string[];
};
export type TSecretApprovalRequest<
T extends unknown = TSecretApprovalSecChangeData,
J extends unknown = EncryptedSecret
> = {
_id: string;
committer: string;
reviewers: {
member: string;
status: ApprovalStatus;
}[];
workspace: string;
environment: string;
folderId: string;
hasMerged: boolean;
status: "open" | "close";
policy: TSecretApprovalPolicy;
commits: {
// if there is no secret means it was creation
secret?: J;
// if there is no new version its for Delete
newVersion?: T;
op: CommitType;
}[];
};
export type TGetSecretApprovalRequestList = {
workspaceId: string;
environment?: string;
};
export type TGetSecretApprovalRequestDetails = {
id: string;
decryptKey: UserWsKeyPair;
};
export type TUpdateSecretApprovalRequestStatusDTO = {
status: ApprovalStatus;
id: string;
};
+4 -1
View File
@@ -26,7 +26,10 @@ export const secretKeys = {
getSecretVersion: (secretId: string) => [{ secretId }, "secret-versions"] as const
};
const decryptSecrets = (encryptedSecrets: EncryptedSecret[], decryptFileKey: UserWsKeyPair) => {
export const decryptSecrets = (
encryptedSecrets: EncryptedSecret[],
decryptFileKey: UserWsKeyPair
) => {
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
const key = decryptAssymmetric({
ciphertext: decryptFileKey.encryptedKey,
+7 -1
View File
@@ -5,13 +5,19 @@ export type { TCloudIntegration, TIntegration } from "./integrations/types";
export type { UserWsKeyPair } from "./keys/types";
export type { Organization } from "./organization/types";
export type { TSecretApprovalPolicy } from "./secretApproval/types";
export type {
TGetSecretApprovalRequestDetails,
TSecretApprovalRequest,
TSecretApprovalSecChange
} from "./secretApprovalRequest/types";
export { ApprovalStatus, CommitType } from "./secretApprovalRequest/types";
export type { TSecretFolder } from "./secretFolders/types";
export type { TImportedSecrets, TSecretImports } from "./secretImports/types";
export * from "./secrets/types";
export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types";
export type { SubscriptionPlan } from "./subscriptions/types";
export type { WsTag } from "./tags/types";
export type { AddUserToWsDTO, AddUserToWsRes, OrgUser, User } from "./users/types";
export type { AddUserToWsDTO, AddUserToWsRes, OrgUser, TWorkspaceUser, User } from "./users/types";
export type { TWebhook } from "./webhooks/types";
export type {
CreateEnvironmentDTO,