From 4c1324baa97fff73096b7e6dbba48d3039e14a32 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 26 Sep 2023 12:25:23 +0530 Subject: [PATCH] feat: added support for getting imported secrets in v3 getSecret api --- .../src/controllers/v3/secretsController.ts | 10 ++-- backend/src/helpers/secrets.ts | 11 +++- .../services/SecretService/index.ts | 3 +- backend/src/services/SecretImportService.ts | 52 +++++++++++++++++++ backend/src/validation/secrets.ts | 12 ++++- 5 files changed, 79 insertions(+), 9 deletions(-) diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index a528436af..a553315bd 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -146,7 +146,7 @@ export const getSecretsRaw = async (req: Request, res: Response) => { */ export const getSecretByNameRaw = async (req: Request, res: Response) => { const { - query: { secretPath, environment, workspaceId, type }, + query: { secretPath, environment, workspaceId, type, include_imports }, params: { secretName } } = await validateRequest(reqValidator.GetSecretByNameRawV3, req); @@ -172,7 +172,8 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => { environment, type, secretPath, - authData: req.authData + authData: req.authData, + include_imports }); const key = await BotService.getWorkspaceKeyWithBot({ @@ -483,7 +484,7 @@ export const getSecrets = async (req: Request, res: Response) => { */ export const getSecretByName = async (req: Request, res: Response) => { const { - query: { secretPath, environment, workspaceId, type }, + query: { secretPath, environment, workspaceId, type, include_imports }, params: { secretName } } = await validateRequest(reqValidator.GetSecretByNameV3, req); @@ -509,7 +510,8 @@ export const getSecretByName = async (req: Request, res: Response) => { environment, type, secretPath, - authData: req.authData + authData: req.authData, + include_imports }); return res.status(200).send({ diff --git a/backend/src/helpers/secrets.ts b/backend/src/helpers/secrets.ts index 3799dc1e7..5b4c8b465 100644 --- a/backend/src/helpers/secrets.ts +++ b/backend/src/helpers/secrets.ts @@ -48,6 +48,7 @@ import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/aut import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService"; import picomatch from "picomatch"; import path from "path"; +import { getAnImportedSecret } from "../services/SecretImportService"; export const isValidScope = ( authPayload: IServiceTokenData, @@ -622,13 +623,14 @@ export const getSecretHelper = async ({ environment, type, authData, - secretPath = "/" + secretPath = "/", + include_imports = true }: GetSecretParams) => { const secretBlindIndex = await generateSecretBlindIndexHelper({ secretName, workspaceId: new Types.ObjectId(workspaceId) }); - let secret: ISecret | null = null; + let secret: ISecret | null | undefined = null; // if using service token filter towards the folderId by secretpath const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); @@ -655,6 +657,11 @@ export const getSecretHelper = async ({ }).lean(); } + if (!secret && include_imports) { + // if still no secret found search in imported secret and retreive + secret = await getAnImportedSecret(secretName, workspaceId.toString(), environment, folderId); + } + if (!secret) throw SecretNotFoundError(); // (EE) create (audit) log diff --git a/backend/src/interfaces/services/SecretService/index.ts b/backend/src/interfaces/services/SecretService/index.ts index 9ea82ce94..f1f89a83b 100644 --- a/backend/src/interfaces/services/SecretService/index.ts +++ b/backend/src/interfaces/services/SecretService/index.ts @@ -19,7 +19,7 @@ export interface CreateSecretParams { secretPath: string; metadata?: { source?: string; - } + }; } export interface GetSecretsParams { @@ -37,6 +37,7 @@ export interface GetSecretParams { environment: string; type?: "shared" | "personal"; authData: AuthData; + include_imports?: boolean; } export interface UpdateSecretParams { diff --git a/backend/src/services/SecretImportService.ts b/backend/src/services/SecretImportService.ts index b432976fc..f23cd2018 100644 --- a/backend/src/services/SecretImportService.ts +++ b/backend/src/services/SecretImportService.ts @@ -1,9 +1,61 @@ import { Types } from "mongoose"; +import { generateSecretBlindIndexHelper } from "../helpers"; import { Folder, ISecret, Secret, SecretImport } from "../models"; import { getFolderByPath } from "./FolderService"; type TSecretImportFid = { environment: string; folderId: string; secretPath: string }; +export const getAnImportedSecret = async ( + secretName: string, + workspaceId: string, + environment: string, + folderId = "root" +) => { + const secretBlindIndex = await generateSecretBlindIndexHelper({ + secretName, + workspaceId: new Types.ObjectId(workspaceId) + }); + + const secImports = await SecretImport.findOne({ + workspace: workspaceId, + environment, + folderId + }); + if (!secImports) return; + if (secImports.imports.length === 0) return; + const folders = await Folder.find({ + workspace: workspaceId, + environment: { $in: secImports.imports.map((el) => el.environment) } + }); + + const importedSecByFid: TSecretImportFid[] = []; + secImports.imports.forEach((el) => { + const folder = folders.find((fl) => fl.environment === el.environment); + if (folder) { + const secPathFolder = getFolderByPath(folder.nodes, el.secretPath); + if (secPathFolder) + importedSecByFid.push({ + environment: el.environment, + folderId: secPathFolder.id, + secretPath: el.secretPath + }); + } else { + if (el.secretPath === "/") { + // this happens when importing with a fresh env without any folders + importedSecByFid.push({ environment: el.environment, folderId: "root", secretPath: "/" }); + } + } + }); + if (importedSecByFid.length === 0) return; + + const secret = await Secret.findOne({ + workspace: workspaceId, + secretBlindIndex + }).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))); + + return secret; +}; + export const getAllImportedSecrets = async ( workspaceId: string, environment: string, diff --git a/backend/src/validation/secrets.ts b/backend/src/validation/secrets.ts index 28e7f469d..18579aa27 100644 --- a/backend/src/validation/secrets.ts +++ b/backend/src/validation/secrets.ts @@ -244,7 +244,11 @@ export const GetSecretByNameRawV3 = z.object({ workspaceId: z.string().trim(), environment: z.string().trim(), secretPath: z.string().trim().default("/"), - type: z.enum([SECRET_SHARED, SECRET_PERSONAL]).optional() + type: z.enum([SECRET_SHARED, SECRET_PERSONAL]).optional(), + include_imports: z + .enum(["true", "false"]) + .default("true") + .transform((value) => value === "true") }) }); @@ -305,7 +309,11 @@ export const GetSecretByNameV3 = z.object({ workspaceId: z.string().trim(), environment: z.string().trim(), secretPath: z.string().trim().default("/"), - type: z.enum([SECRET_SHARED, SECRET_PERSONAL]).optional() + type: z.enum([SECRET_SHARED, SECRET_PERSONAL]).optional(), + include_imports: z + .enum(["true", "false"]) + .default("true") + .transform((value) => value === "true") }), params: z.object({ secretName: z.string().trim()