Merge pull request #1078 from akhilmhdh/feat/secret-bug

feat: added support for recursive file creation
This commit is contained in:
Maidul Islam
2023-10-13 15:57:50 +01:00
committed by GitHub
13 changed files with 138 additions and 66 deletions
@@ -9,7 +9,6 @@ import { Secret, ServiceTokenData } from "../../models";
import { Folder } from "../../models/folder";
import {
appendFolder,
generateFolderId,
getAllFolderIds,
getFolderByPath,
getFolderWithPathFromId,
@@ -132,9 +131,6 @@ export const createFolder = async (req: Request, res: Response) => {
// space has no folders initialized
if (!folders) {
if (directory !== "/") throw ERR_FOLDER_NOT_FOUND;
const id = generateFolderId();
const folder = new Folder({
workspace: workspaceId,
environment,
@@ -142,14 +138,15 @@ export const createFolder = async (req: Request, res: Response) => {
id: "root",
name: "root",
version: 1,
children: [{ id, name: folderName, children: [], version: 1 }]
children: []
}
});
const { parent, child } = appendFolder(folder.nodes, { folderName, directory });
await folder.save();
const folderVersion = new FolderVersion({
workspace: workspaceId,
environment,
nodes: folder.nodes
nodes: parent
});
await folderVersion.save();
await EESecretService.takeSecretSnapshot({
@@ -163,9 +160,9 @@ export const createFolder = async (req: Request, res: Response) => {
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: id,
folderId: child.id,
folderName,
folderPath: `root/${folderName}`
folderPath: directory
}
},
{
@@ -173,26 +170,26 @@ export const createFolder = async (req: Request, res: Response) => {
}
);
return res.json({ folder: { id, name: folderName } });
return res.json({ folder: { id: child.id, name: folderName } });
}
const parentFolder = getFolderByPath(folders.nodes, directory);
if (!parentFolder) throw ERR_FOLDER_NOT_FOUND;
const { parent, child, hasCreated } = appendFolder(folders.nodes, { folderName, directory });
if (!hasCreated) return res.json({ folder: child });
const folder = appendFolder(folders.nodes, { folderName, parentFolderId: parentFolder.id });
await Folder.findByIdAndUpdate(folders._id, folders);
const folderVersion = new FolderVersion({
workspace: workspaceId,
environment,
nodes: parentFolder
nodes: parent
});
await folderVersion.save();
await EESecretService.takeSecretSnapshot({
workspaceId: new Types.ObjectId(workspaceId),
environment,
folderId: parentFolder.id
folderId: child.id
});
await EEAuditLogService.createAuditLog(
@@ -201,7 +198,7 @@ export const createFolder = async (req: Request, res: Response) => {
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderId: child.id,
folderName,
folderPath: directory
}
@@ -211,7 +208,7 @@ export const createFolder = async (req: Request, res: Response) => {
}
);
return res.json({ folder });
return res.json({ folder: child });
};
/**
@@ -777,7 +777,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
*/
export const deleteSecretByName = async (req: Request, res: Response) => {
const {
body: { type, environment, secretPath, workspaceId },
body: { type, environment, secretPath, workspaceId, secretId },
params: { secretName }
} = await validateRequest(reqValidator.DeleteSecretByNameV3, req);
@@ -813,6 +813,7 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
const { secret } = await SecretService.deleteSecret({
secretName,
secretId,
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
+32 -19
View File
@@ -57,10 +57,10 @@ import { getAnImportedSecret } from "../services/SecretImportService";
/**
* Validate scope for service token v3
* @param authPayload
* @param environment
* @param secretPath
* @returns
* @param authPayload
* @param environment
* @param secretPath
* @returns
*/
export const isValidScopeV3 = ({
authPayload,
@@ -68,37 +68,40 @@ export const isValidScopeV3 = ({
secretPath,
requiredPermissions
}: {
authPayload: IServiceTokenDataV3,
environment: string,
secretPath: string,
requiredPermissions: Permission[]
authPayload: IServiceTokenDataV3;
environment: string;
secretPath: string;
requiredPermissions: Permission[];
}) => {
const { scopes } = authPayload;
const validScope = scopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (validScope && !requiredPermissions.every(permission => validScope.permissions.includes(permission))) {
if (
validScope &&
!requiredPermissions.every((permission) => validScope.permissions.includes(permission))
) {
return false;
}
return Boolean(validScope);
}
};
/**
* Validate scope for service token v2
* @param authPayload
* @param environment
* @param secretPath
* @returns
* @param authPayload
* @param environment
* @param secretPath
* @returns
*/
export const isValidScope = (
authPayload: IServiceTokenData,
environment: string,
secretPath: string,
secretPath: string
) => {
const { scopes: tkScopes } = authPayload;
const validScope = tkScopes.find(
@@ -1000,12 +1003,22 @@ export const deleteSecretHelper = async ({
environment,
type,
authData,
secretPath = "/"
secretPath = "/",
// used for update corner case and blindIndex goes wrong way
secretId
}: DeleteSecretParams) => {
const secretBlindIndex = await generateSecretBlindIndexHelper({
let secretBlindIndex = await generateSecretBlindIndexHelper({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
});
if (secretId) {
const secret = await Secret.findOne({
workspace: workspaceId,
environment,
_id: secretId
}).select("secretBlindIndex");
if (secret && secret.secretBlindIndex) secretBlindIndex = secret.secretBlindIndex;
}
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
@@ -64,6 +64,7 @@ export interface UpdateSecretParams {
export interface DeleteSecretParams {
secretName: string;
secretId?: string;
workspaceId: Types.ObjectId;
environment: string;
type: "shared" | "personal";
+22 -15
View File
@@ -5,7 +5,7 @@ import path from "path";
type TAppendFolderDTO = {
folderName: string;
parentFolderId?: string;
directory: string;
};
type TRenameFolderDTO = {
@@ -50,9 +50,8 @@ export const folderBfsTraversal = async (
// bfs and then append to the folder
const appendChild = (folders: TFolderSchema, folderName: string) => {
const folder = folders.children.find(({ name }) => name === folderName);
if (folder) {
throw new Error("Folder already exists");
}
if (folder) return { folder, hasCreated: false };
const id = generateFolderId();
folders.version += 1;
folders.children.push({
@@ -61,24 +60,32 @@ const appendChild = (folders: TFolderSchema, folderName: string) => {
children: [],
version: 1
});
return { id, name: folderName };
// last element that is the new one
return { folder: folders.children[folders.children.length - 1], hasCreated: true };
};
// root of append child wrapper
export const appendFolder = (
folders: TFolderSchema,
{ folderName, parentFolderId }: TAppendFolderDTO
) => {
const isRoot = !parentFolderId;
{ folderName, directory }: TAppendFolderDTO
): { parent: TFolderSchema; child: TFolderSchema; hasCreated?: boolean } => {
if (directory === "/") {
const newFolder = appendChild(folders, folderName);
return { parent: folders, child: newFolder.folder, hasCreated: newFolder.hasCreated };
}
if (isRoot) {
return appendChild(folders, folderName);
const segments = directory.split("/").filter(Boolean);
const segment = segments.shift();
if (segment) {
const nestedFolders = appendChild(folders, segment);
return appendFolder(nestedFolders.folder, {
folderName,
directory: path.join("/", ...segments)
});
}
const folder = searchByFolderId(folders, parentFolderId);
if (!folder) {
throw new Error("Parent Folder not found");
}
return appendChild(folder, folderName);
const newFolder = appendChild(folders, folderName);
return { parent: folders, child: newFolder.folder, hasCreated: newFolder.hasCreated };
};
export const renameFolder = (
+2 -1
View File
@@ -379,7 +379,8 @@ export const DeleteSecretByNameV3 = z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
type: z.enum([SECRET_SHARED, SECRET_PERSONAL]),
secretPath: z.string().trim().default("/")
secretPath: z.string().trim().default("/"),
secretId: z.string().trim().optional()
}),
params: z.object({
secretName: z.string()