mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 18:28:12 +00:00
feat: implemented service token support for folder and secret import api
This commit is contained in:
@@ -1,15 +1,55 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { validateMembership } from "../../helpers";
|
import path from "path";
|
||||||
import { Folder, SecretImport } from "../../models";
|
import { isValidScope, validateMembership } from "../../helpers";
|
||||||
|
import { ServiceTokenData } from "../../models";
|
||||||
|
import Folder, { TFolderRootSchema } from "../../models/folder";
|
||||||
|
import SecretImport from "../../models/secretImports";
|
||||||
|
import { searchByFolderIdWithDir } from "../../services/FolderService";
|
||||||
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
||||||
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
import { BadRequestError, ResourceNotFoundError,UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import { ADMIN, MEMBER } from "../../variables";
|
import { ADMIN, MEMBER } from "../../variables";
|
||||||
import { EEAuditLogService } from "../../ee/services";
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
import { EventType } from "../../ee/models";
|
import { EventType } from "../../ee/models";
|
||||||
import { getFolderPath } from "../../services/FolderService";
|
import { getFolderPath } from "../../services/FolderService";
|
||||||
|
|
||||||
|
const getFolderWithPathFromId = (folders: TFolderRootSchema, parentFolderId: string) => {
|
||||||
|
const search = searchByFolderIdWithDir(folders.nodes, parentFolderId);
|
||||||
|
if (!search) {
|
||||||
|
throw { message: "Folder permission denied" };
|
||||||
|
}
|
||||||
|
const { folder, dir } = search;
|
||||||
|
const folderPath = path.join(
|
||||||
|
"/",
|
||||||
|
...dir.filter(({ name }) => name !== "root").map(({ name }) => name)
|
||||||
|
);
|
||||||
|
return { folder, folderPath, dir };
|
||||||
|
};
|
||||||
|
|
||||||
export const createSecretImport = async (req: Request, res: Response) => {
|
export const createSecretImport = async (req: Request, res: Response) => {
|
||||||
const { workspaceId, environment, folderId, secretImport } = req.body;
|
const { workspaceId, environment, folderId, secretImport } = req.body;
|
||||||
|
|
||||||
|
const folders = await Folder.findOne({
|
||||||
|
workspace: workspaceId,
|
||||||
|
environment
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
if (!folders && folderId !== "root") {
|
||||||
|
throw BadRequestError({ message: "Folder doesn't exist" });
|
||||||
|
}
|
||||||
|
|
||||||
|
let secretPath = "/";
|
||||||
|
if (folders) {
|
||||||
|
const { folderPath } = getFolderWithPathFromId(folders, folderId);
|
||||||
|
secretPath = folderPath;
|
||||||
|
}
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
// root check
|
||||||
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const importSecDoc = await SecretImport.findOne({
|
const importSecDoc = await SecretImport.findOne({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
@@ -99,11 +139,34 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "Import not found" });
|
throw BadRequestError({ message: "Import not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
await validateMembership({
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
userId: req.user._id.toString(),
|
await validateMembership({
|
||||||
workspaceId: importSecDoc.workspace,
|
userId: req.user._id.toString(),
|
||||||
acceptedRoles: [ADMIN, MEMBER]
|
workspaceId: importSecDoc.workspace,
|
||||||
});
|
acceptedRoles: [ADMIN, MEMBER]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// check for service token validity
|
||||||
|
const folders = await Folder.findOne({
|
||||||
|
workspace: importSecDoc.workspace,
|
||||||
|
environment: importSecDoc.environment
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
let secretPath = "/";
|
||||||
|
if (folders) {
|
||||||
|
const { folderPath } = getFolderWithPathFromId(folders, importSecDoc.folderId);
|
||||||
|
secretPath = folderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
importSecDoc.environment,
|
||||||
|
secretPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const orderBefore = importSecDoc.imports;
|
const orderBefore = importSecDoc.imports;
|
||||||
importSecDoc.imports = secretImports;
|
importSecDoc.imports = secretImports;
|
||||||
@@ -149,11 +212,34 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "Import not found" });
|
throw BadRequestError({ message: "Import not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
await validateMembership({
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
userId: req.user._id.toString(),
|
await validateMembership({
|
||||||
workspaceId: importSecDoc.workspace,
|
userId: req.user._id.toString(),
|
||||||
acceptedRoles: [ADMIN, MEMBER]
|
workspaceId: importSecDoc.workspace,
|
||||||
});
|
acceptedRoles: [ADMIN, MEMBER]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// check for service token validity
|
||||||
|
const folders = await Folder.findOne({
|
||||||
|
workspace: importSecDoc.workspace,
|
||||||
|
environment: importSecDoc.environment
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
let secretPath = "/";
|
||||||
|
if (folders) {
|
||||||
|
const { folderPath } = getFolderWithPathFromId(folders, importSecDoc.folderId);
|
||||||
|
secretPath = folderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
importSecDoc.environment,
|
||||||
|
secretPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
importSecDoc.imports = importSecDoc.imports.filter(
|
importSecDoc.imports = importSecDoc.imports.filter(
|
||||||
({ environment, secretPath }) =>
|
({ environment, secretPath }) =>
|
||||||
!(environment === secretImportEnv && secretPath === secretImportPath)
|
!(environment === secretImportEnv && secretPath === secretImportPath)
|
||||||
@@ -204,6 +290,29 @@ export const getSecretImports = async (req: Request, res: Response) => {
|
|||||||
return res.status(200).json({ secretImport: {} });
|
return res.status(200).json({ secretImport: {} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
// check for service token validity
|
||||||
|
const folders = await Folder.findOne({
|
||||||
|
workspace: importSecDoc.workspace,
|
||||||
|
environment: importSecDoc.environment
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
let secretPath = "/";
|
||||||
|
if (folders) {
|
||||||
|
const { folderPath } = getFolderWithPathFromId(folders, importSecDoc.folderId);
|
||||||
|
secretPath = folderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
importSecDoc.environment,
|
||||||
|
secretPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res.status(200).json({ secretImport: importSecDoc });
|
return res.status(200).json({ secretImport: importSecDoc });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -223,6 +332,29 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
|||||||
return res.status(200).json({ secrets: [] });
|
return res.status(200).json({ secrets: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
// check for service token validity
|
||||||
|
const folders = await Folder.findOne({
|
||||||
|
workspace: importSecDoc.workspace,
|
||||||
|
environment: importSecDoc.environment
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
let secretPath = "/";
|
||||||
|
if (folders) {
|
||||||
|
const { folderPath } = getFolderWithPathFromId(folders, importSecDoc.folderId);
|
||||||
|
secretPath = folderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
importSecDoc.environment,
|
||||||
|
secretPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Secret } from "../../models";
|
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import Folder from "../../models/folder";
|
import path from "path";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { EventType, FolderVersion } from "../../ee/models";
|
||||||
|
import { EEAuditLogService, EESecretService } from "../../ee/services";
|
||||||
|
import { validateMembership } from "../../helpers/membership";
|
||||||
|
import { isValidScope } from "../../helpers/secrets";
|
||||||
|
import { Secret, ServiceTokenData } from "../../models";
|
||||||
|
import Folder, { TFolderRootSchema } from "../../models/folder";
|
||||||
import {
|
import {
|
||||||
appendFolder,
|
appendFolder,
|
||||||
deleteFolderById,
|
deleteFolderById,
|
||||||
@@ -11,31 +15,50 @@ import {
|
|||||||
getFolderByPath,
|
getFolderByPath,
|
||||||
getFolderPath,
|
getFolderPath,
|
||||||
getParentFromFolderId,
|
getParentFromFolderId,
|
||||||
searchByFolderId,
|
|
||||||
searchByFolderIdWithDir,
|
searchByFolderIdWithDir,
|
||||||
validateFolderName,
|
validateFolderName
|
||||||
} from "../../services/FolderService";
|
} from "../../services/FolderService";
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import { ADMIN, MEMBER } from "../../variables";
|
import { ADMIN, MEMBER } from "../../variables";
|
||||||
import { validateMembership } from "../../helpers/membership";
|
|
||||||
import { EventType, FolderVersion } from "../../ee/models";
|
const getFolderWithPathFromId = (folders: TFolderRootSchema, parentFolderId: string) => {
|
||||||
import { EEAuditLogService, EESecretService } from "../../ee/services";
|
const search = searchByFolderIdWithDir(folders.nodes, parentFolderId);
|
||||||
|
if (!search) {
|
||||||
|
throw { message: "Folder permission denied" };
|
||||||
|
}
|
||||||
|
const { folder, dir } = search;
|
||||||
|
const folderPath = path.join(
|
||||||
|
"/",
|
||||||
|
...dir.filter(({ name }) => name !== "root").map(({ name }) => name)
|
||||||
|
);
|
||||||
|
return { folder, folderPath, dir };
|
||||||
|
};
|
||||||
|
|
||||||
// verify workspace id/environment
|
// verify workspace id/environment
|
||||||
export const createFolder = async (req: Request, res: Response) => {
|
export const createFolder = async (req: Request, res: Response) => {
|
||||||
const { workspaceId, environment, folderName, parentFolderId } = req.body;
|
const { workspaceId, environment, folderName, parentFolderId } = req.body;
|
||||||
if (!validateFolderName(folderName)) {
|
if (!validateFolderName(folderName)) {
|
||||||
throw BadRequestError({
|
throw BadRequestError({
|
||||||
message: "Folder name cannot contain spaces. Only underscore and dashes",
|
message: "Folder name cannot contain spaces. Only underscore and dashes"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const folders = await Folder.findOne({
|
const folders = await Folder.findOne({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment
|
||||||
}).lean();
|
}).lean();
|
||||||
|
|
||||||
// space has no folders initialized
|
// space has no folders initialized
|
||||||
|
|
||||||
if (!folders) {
|
if (!folders) {
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
// root check
|
||||||
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, "/");
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const id = generateFolderId();
|
const id = generateFolderId();
|
||||||
const folder = new Folder({
|
const folder = new Folder({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
@@ -44,19 +67,19 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
id: "root",
|
id: "root",
|
||||||
name: "root",
|
name: "root",
|
||||||
version: 1,
|
version: 1,
|
||||||
children: [{ id, name: folderName, children: [], version: 1 }],
|
children: [{ id, name: folderName, children: [], version: 1 }]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
await folder.save();
|
await folder.save();
|
||||||
const folderVersion = new FolderVersion({
|
const folderVersion = new FolderVersion({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
nodes: folder.nodes,
|
nodes: folder.nodes
|
||||||
});
|
});
|
||||||
await folderVersion.save();
|
await folderVersion.save();
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment
|
||||||
});
|
});
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
@@ -82,19 +105,36 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
await Folder.findByIdAndUpdate(folders._id, folders);
|
await Folder.findByIdAndUpdate(folders._id, folders);
|
||||||
|
|
||||||
const parentFolder = searchByFolderId(folders.nodes, parentFolderId);
|
const { folder: parentFolder, folderPath: parentFolderPath } = getFolderWithPathFromId(
|
||||||
|
folders,
|
||||||
|
parentFolderId || "root"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
// root check
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
environment,
|
||||||
|
parentFolderPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Folder.findByIdAndUpdate(folders._id, folders);
|
||||||
|
|
||||||
const folderVersion = new FolderVersion({
|
const folderVersion = new FolderVersion({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
nodes: parentFolder,
|
nodes: parentFolder
|
||||||
});
|
});
|
||||||
await folderVersion.save();
|
await folderVersion.save();
|
||||||
|
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
folderId: parentFolderId,
|
folderId: parentFolderId
|
||||||
});
|
});
|
||||||
|
|
||||||
const folderPath = await getFolderPath(folders, folder.id);
|
const folderPath = await getFolderPath(folders, folder.id);
|
||||||
@@ -121,18 +161,25 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
export const updateFolderById = async (req: Request, res: Response) => {
|
export const updateFolderById = async (req: Request, res: Response) => {
|
||||||
const { folderId } = req.params;
|
const { folderId } = req.params;
|
||||||
const { name, workspaceId, environment } = req.body;
|
const { name, workspaceId, environment } = req.body;
|
||||||
|
if (!validateFolderName(name)) {
|
||||||
|
throw BadRequestError({
|
||||||
|
message: "Folder name cannot contain spaces. Only underscore and dashes"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||||
if (!folders) {
|
if (!folders) {
|
||||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that user is a member of the workspace
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
await validateMembership({
|
// check that user is a member of the workspace
|
||||||
userId: req.user._id.toString(),
|
await validateMembership({
|
||||||
workspaceId,
|
userId: req.user._id.toString(),
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
workspaceId,
|
||||||
});
|
acceptedRoles: [ADMIN, MEMBER]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const parentFolder = getParentFromFolderId(folders.nodes, folderId);
|
const parentFolder = getParentFromFolderId(folders.nodes, folderId);
|
||||||
if (!parentFolder) {
|
if (!parentFolder) {
|
||||||
@@ -144,7 +191,15 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldFolderName = folder.name;
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
const { folderPath: secretPath } = getFolderWithPathFromId(folders, parentFolder.id);
|
||||||
|
// root check
|
||||||
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parentFolder.version += 1;
|
parentFolder.version += 1;
|
||||||
folder.name = name;
|
folder.name = name;
|
||||||
|
|
||||||
@@ -152,14 +207,14 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
const folderVersion = new FolderVersion({
|
const folderVersion = new FolderVersion({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
nodes: parentFolder,
|
nodes: parentFolder
|
||||||
});
|
});
|
||||||
await folderVersion.save();
|
await folderVersion.save();
|
||||||
|
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
folderId: parentFolder.id,
|
folderId: parentFolder.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const folderPath = await getFolderPath(folders, folder.id);
|
const folderPath = await getFolderPath(folders, folder.id);
|
||||||
@@ -183,7 +238,7 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
message: "Successfully updated folder",
|
message: "Successfully updated folder",
|
||||||
folder: { name: folder.name, id: folder.id },
|
folder: { name: folder.name, id: folder.id }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -196,12 +251,14 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that user is a member of the workspace
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
await validateMembership({
|
// check that user is a member of the workspace
|
||||||
userId: req.user._id.toString(),
|
await validateMembership({
|
||||||
workspaceId,
|
userId: req.user._id.toString(),
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
workspaceId,
|
||||||
});
|
acceptedRoles: [ADMIN, MEMBER]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const folderPath = await getFolderPath(folders, folderId);
|
const folderPath = await getFolderPath(folders, folderId);
|
||||||
|
|
||||||
@@ -211,6 +268,14 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
const { deletedNode: delFolder, parent: parentFolder } = delOp;
|
const { deletedNode: delFolder, parent: parentFolder } = delOp;
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
const { folderPath: secretPath } = getFolderWithPathFromId(folders, parentFolder.id);
|
||||||
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parentFolder.version += 1;
|
parentFolder.version += 1;
|
||||||
const delFolderIds = getAllFolderIds(delFolder);
|
const delFolderIds = getAllFolderIds(delFolder);
|
||||||
|
|
||||||
@@ -218,21 +283,21 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
const folderVersion = new FolderVersion({
|
const folderVersion = new FolderVersion({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
nodes: parentFolder,
|
nodes: parentFolder
|
||||||
});
|
});
|
||||||
await folderVersion.save();
|
await folderVersion.save();
|
||||||
if (delFolderIds.length) {
|
if (delFolderIds.length) {
|
||||||
await Secret.deleteMany({
|
await Secret.deleteMany({
|
||||||
folder: { $in: delFolderIds.map(({ id }) => id) },
|
folder: { $in: delFolderIds.map(({ id }) => id) },
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
folderId: parentFolder.id,
|
folderId: parentFolder.id
|
||||||
});
|
});
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
@@ -256,13 +321,12 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// TODO: validate workspace
|
// TODO: validate workspace
|
||||||
export const getFolders = async (req: Request, res: Response) => {
|
export const getFolders = async (req: Request, res: Response) => {
|
||||||
const { workspaceId, environment, parentFolderId, parentFolderPath } =
|
const { workspaceId, environment, parentFolderId, parentFolderPath } = req.query as {
|
||||||
req.query as {
|
workspaceId: string;
|
||||||
workspaceId: string;
|
environment: string;
|
||||||
environment: string;
|
parentFolderId?: string;
|
||||||
parentFolderId?: string;
|
parentFolderPath?: string;
|
||||||
parentFolderPath?: string;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||||
if (!folders) {
|
if (!folders) {
|
||||||
@@ -270,16 +334,29 @@ export const getFolders = async (req: Request, res: Response) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that user is a member of the workspace
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
await validateMembership({
|
// check that user is a member of the workspace
|
||||||
userId: req.user._id.toString(),
|
await validateMembership({
|
||||||
workspaceId,
|
userId: req.user._id.toString(),
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
workspaceId,
|
||||||
});
|
acceptedRoles: [ADMIN, MEMBER]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// if instead of parentFolderId given a path like /folder1/folder2
|
// if instead of parentFolderId given a path like /folder1/folder2
|
||||||
if (parentFolderPath) {
|
if (parentFolderPath) {
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
const isValidScopeAccess = isValidScope(
|
||||||
|
req.authData.authPayload,
|
||||||
|
environment,
|
||||||
|
parentFolderPath
|
||||||
|
);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
const folder = getFolderByPath(folders.nodes, parentFolderPath);
|
const folder = getFolderByPath(folders.nodes, parentFolderPath);
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
res.send({ folders: [], dir: [] });
|
res.send({ folders: [], dir: [] });
|
||||||
return;
|
return;
|
||||||
@@ -287,27 +364,36 @@ export const getFolders = async (req: Request, res: Response) => {
|
|||||||
// dir is not needed at present as this is only used in overview section of secrets
|
// dir is not needed at present as this is only used in overview section of secrets
|
||||||
res.send({
|
res.send({
|
||||||
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
||||||
dir: [{ name: folder.name, id: folder.id }],
|
dir: [{ name: folder.name, id: folder.id }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parentFolderId) {
|
if (!parentFolderId) {
|
||||||
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, "/");
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const rootFolders = folders.nodes.children.map(({ id, name }) => ({
|
const rootFolders = folders.nodes.children.map(({ id, name }) => ({
|
||||||
id,
|
id,
|
||||||
name,
|
name
|
||||||
}));
|
}));
|
||||||
res.send({ folders: rootFolders });
|
res.send({ folders: rootFolders });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const folderBySearch = searchByFolderIdWithDir(folders.nodes, parentFolderId);
|
const { folder, folderPath, dir } = getFolderWithPathFromId(folders, parentFolderId);
|
||||||
if (!folderBySearch) {
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, folderPath);
|
||||||
|
if (!isValidScopeAccess) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const { folder, dir } = folderBySearch;
|
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
||||||
dir,
|
dir
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
const router = express.Router();
|
|
||||||
import { body, param, query } from "express-validator";
|
import { body, param, query } from "express-validator";
|
||||||
import { secretImportController } from "../../controllers/v1";
|
import { secretImportController } from "../../controllers/v1";
|
||||||
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT]
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
requireWorkspaceAuth({
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
@@ -27,7 +27,7 @@ router.post(
|
|||||||
router.put(
|
router.put(
|
||||||
"/:id",
|
"/:id",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT]
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
param("id").exists().isString().trim(),
|
param("id").exists().isString().trim(),
|
||||||
body("secretImports").exists().isArray(),
|
body("secretImports").exists().isArray(),
|
||||||
@@ -40,7 +40,7 @@ router.put(
|
|||||||
router.delete(
|
router.delete(
|
||||||
"/:id",
|
"/:id",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT]
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
param("id").exists().isString().trim(),
|
param("id").exists().isString().trim(),
|
||||||
body("secretImportPath").isString().exists().trim(),
|
body("secretImportPath").isString().exists().trim(),
|
||||||
@@ -52,7 +52,7 @@ router.delete(
|
|||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT]
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
requireWorkspaceAuth({
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
@@ -68,7 +68,7 @@ router.get(
|
|||||||
router.get(
|
router.get(
|
||||||
"/secrets",
|
"/secrets",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT]
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
requireWorkspaceAuth({
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
const router = express.Router();
|
|
||||||
import {
|
|
||||||
requireAuth,
|
|
||||||
requireWorkspaceAuth,
|
|
||||||
validateRequest,
|
|
||||||
} from "../../middleware";
|
|
||||||
import { body, param, query } from "express-validator";
|
import { body, param, query } from "express-validator";
|
||||||
import {
|
import {
|
||||||
createFolder,
|
createFolder,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
getFolders,
|
getFolders,
|
||||||
updateFolderById,
|
updateFolderById
|
||||||
} from "../../controllers/v1/secretsFolderController";
|
} from "../../controllers/v1/secretsFolderController";
|
||||||
|
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT],
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
requireWorkspaceAuth({
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
locationWorkspaceId: "body",
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
body("workspaceId").exists(),
|
body("workspaceId").exists(),
|
||||||
body("environment").exists(),
|
body("environment").exists(),
|
||||||
@@ -34,7 +30,7 @@ router.post(
|
|||||||
router.patch(
|
router.patch(
|
||||||
"/:folderId",
|
"/:folderId",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT],
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
body("workspaceId").exists(),
|
body("workspaceId").exists(),
|
||||||
body("environment").exists(),
|
body("environment").exists(),
|
||||||
@@ -46,7 +42,7 @@ router.patch(
|
|||||||
router.delete(
|
router.delete(
|
||||||
"/:folderId",
|
"/:folderId",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT],
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
body("workspaceId").exists(),
|
body("workspaceId").exists(),
|
||||||
body("environment").exists(),
|
body("environment").exists(),
|
||||||
@@ -58,7 +54,7 @@ router.delete(
|
|||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT],
|
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
query("workspaceId").exists().isString().trim(),
|
query("workspaceId").exists().isString().trim(),
|
||||||
query("environment").exists().isString().trim(),
|
query("environment").exists().isString().trim(),
|
||||||
|
|||||||
Reference in New Issue
Block a user