Merge pull request #825 from akhilmhdh/feat/service-token-folder-api

feat: implemented service token support for folder and secret import api
This commit is contained in:
Maidul Islam
2023-08-08 13:17:54 -04:00
committed by GitHub
5 changed files with 301 additions and 129 deletions
@@ -1,31 +1,49 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { validateMembership } from "../../helpers"; import { isValidScope, validateMembership } from "../../helpers";
import { Folder, SecretImport } from "../../models"; import { ServiceTokenData } from "../../models";
import Folder from "../../models/folder";
import SecretImport from "../../models/secretImports";
import { getAllImportedSecrets } from "../../services/SecretImportService"; import { getAllImportedSecrets } from "../../services/SecretImportService";
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors"; import { getFolderWithPathFromId } from "../../services/FolderService";
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";
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 ResourceNotFoundError({
message: "Failed to find folder"
});
}
let secretPath = "/";
if (folders) {
const { folderPath } = getFolderWithPathFromId(folders.nodes, 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,
folderId folderId
}); });
const folders = await Folder.findOne({ const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, folderId).folderPath:"/";
workspace: workspaceId,
environment,
}).lean();
if (!folders) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const importToSecretPath = await getFolderPath(folders, folderId);
if (!importSecDoc) { if (!importSecDoc) {
const doc = new SecretImport({ const doc = new SecretImport({
@@ -99,11 +117,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.nodes, 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;
@@ -119,7 +160,7 @@ export const updateSecretImport = async (req: Request, res: Response) => {
message: "Failed to find folder" message: "Failed to find folder"
}); });
const importToSecretPath = await getFolderPath(folders, importSecDoc.folderId); const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, importSecDoc.folderId).folderPath:"/";
await EEAuditLogService.createAuditLog( await EEAuditLogService.createAuditLog(
req.authData, req.authData,
@@ -149,11 +190,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.nodes, 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)
@@ -169,7 +233,7 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
message: "Failed to find folder" message: "Failed to find folder"
}); });
const importToSecretPath = await getFolderPath(folders, importSecDoc.folderId); const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, importSecDoc.folderId).folderPath:"/";
await EEAuditLogService.createAuditLog( await EEAuditLogService.createAuditLog(
req.authData, req.authData,
@@ -204,6 +268,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.nodes, 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 +310,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.nodes, 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,41 +1,49 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Secret } from "../../models";
import { Types } from "mongoose"; import { Types } from "mongoose";
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 from "../../models/folder"; import Folder from "../../models/folder";
import { BadRequestError } from "../../utils/errors";
import { import {
appendFolder, appendFolder,
deleteFolderById, deleteFolderById,
generateFolderId, generateFolderId,
getAllFolderIds, getAllFolderIds,
getFolderByPath, getFolderByPath,
getFolderPath, getFolderWithPathFromId,
getParentFromFolderId, getParentFromFolderId,
searchByFolderId, validateFolderName
searchByFolderIdWithDir,
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";
import { EEAuditLogService, EESecretService } from "../../ee/services";
// 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 +52,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(
@@ -81,23 +89,40 @@ export const createFolder = async (req: Request, res: Response) => {
const folder = appendFolder(folders.nodes, { folderName, parentFolderId }); const folder = appendFolder(folders.nodes, { folderName, parentFolderId });
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.nodes,
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} = getFolderWithPathFromId(folders.nodes, folder.id);
await EEAuditLogService.createAuditLog( await EEAuditLogService.createAuditLog(
req.authData, req.authData,
@@ -121,18 +146,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,6 +176,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" });
} }
if (req.authData.authPayload instanceof ServiceTokenData) {
const { folderPath: secretPath } = getFolderWithPathFromId(folders.nodes, parentFolder.id);
// root check
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
if (!isValidScopeAccess) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
}
const oldFolderName = folder.name; const oldFolderName = folder.name;
parentFolder.version += 1; parentFolder.version += 1;
folder.name = name; folder.name = name;
@@ -152,17 +193,17 @@ 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} = getFolderWithPathFromId(folders.nodes, folder.id);
await EEAuditLogService.createAuditLog( await EEAuditLogService.createAuditLog(
req.authData, req.authData,
@@ -183,7 +224,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,14 +237,16 @@ 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} = getFolderWithPathFromId(folders.nodes, folderId);
const delOp = deleteFolderById(folders.nodes, folderId); const delOp = deleteFolderById(folders.nodes, folderId);
if (!delOp) { if (!delOp) {
@@ -211,6 +254,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.nodes, 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 +269,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 +307,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 +320,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 +350,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.nodes, 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
}); });
}; };
+6 -6
View File
@@ -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],
+8 -12
View File
@@ -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(),
+18 -24
View File
@@ -1,7 +1,7 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { Types } from "mongoose"; import { Types } from "mongoose";
import Folder, { TFolderRootSchema, TFolderSchema } from "../models/folder"; import Folder, { TFolderSchema } from "../models/folder";
import { ResourceNotFoundError } from "../utils/errors"; import path from "path";
type TAppendFolderDTO = { type TAppendFolderDTO = {
folderName: string; folderName: string;
@@ -59,7 +59,7 @@ const appendChild = (folders: TFolderSchema, folderName: string) => {
id, id,
name: folderName, name: folderName,
children: [], children: [],
version: 1, version: 1
}); });
return { id, name: folderName }; return { id, name: folderName };
}; };
@@ -109,10 +109,7 @@ export const deleteFolderById = (folders: TFolderSchema, folderId: string) => {
}; };
// bfs but return parent of the folderID // bfs but return parent of the folderID
export const getParentFromFolderId = ( export const getParentFromFolderId = (folders: TFolderSchema, folderId: string) => {
folders: TFolderSchema,
folderId: string
) => {
const queue = [folders]; const queue = [folders];
while (queue.length) { while (queue.length) {
const folder = queue.pop() as TFolderSchema; const folder = queue.pop() as TFolderSchema;
@@ -141,10 +138,7 @@ export const getAllFolderIds = (folders: TFolderSchema) => {
// We then record the number of childs of each root node // We then record the number of childs of each root node
// When we reach leaf node or when all childs of a root node are visited // When we reach leaf node or when all childs of a root node are visited
// We remove it from path recorded by using the total child record // We remove it from path recorded by using the total child record
export const searchByFolderIdWithDir = ( export const searchByFolderIdWithDir = (folders: TFolderSchema, folderId: string) => {
folders: TFolderSchema,
folderId: string
) => {
const stack = [folders]; const stack = [folders];
const dir: Array<{ id: string; name: string }> = []; const dir: Array<{ id: string; name: string }> = [];
const hits: Record<string, number> = {}; const hits: Record<string, number> = {};
@@ -173,19 +167,19 @@ export const searchByFolderIdWithDir = (
return; return;
}; };
export const getFolderPath = ( // used for get folder path from id
folders: TFolderRootSchema, export const getFolderWithPathFromId = (folders: TFolderSchema, parentFolderId: string) => {
folderId: string const search = searchByFolderIdWithDir(folders, parentFolderId);
) => { if (!search) {
const folderBySearch = searchByFolderIdWithDir(folders.nodes, folderId); throw { message: "Folder permission denied" };
if (!folderBySearch) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const folderPath = folderBySearch.dir.map((folder) => folder.name).join("/");
return folderPath;
} }
const { folder, dir } = search;
const folderPath = path.join(
"/",
...dir.filter(({ name }) => name !== "root").map(({ name }) => name)
);
return { folder, folderPath, dir };
};
// to get folder of a path given // to get folder of a path given
// Like /frontend/folder#1 // Like /frontend/folder#1
@@ -216,7 +210,7 @@ export const getFolderIdFromServiceToken = async (
) => { ) => {
const folders = await Folder.findOne({ const folders = await Folder.findOne({
workspace: workspaceId, workspace: workspaceId,
environment, environment
}); });
if (!folders) { if (!folders) {