add folders to batch and get secrets api

This commit is contained in:
Maidul Islam
2023-04-26 12:53:14 -04:00
parent 492bf39243
commit 242809ce26
5 changed files with 102 additions and 11 deletions
@@ -25,6 +25,8 @@ import {
BatchSecretRequest, BatchSecretRequest,
BatchSecret BatchSecret
} from '../../types/secret'; } from '../../types/secret';
import { getFolderPath, getFoldersInDirectory, normalizePath } from '../../utils/folder';
import { ROOT_FOLDER_PATH } from '../../utils/folder';
/** /**
* Peform a batch of any specified CUD secret operations * Peform a batch of any specified CUD secret operations
@@ -51,13 +53,18 @@ export const batchSecrets = async (req: Request, res: Response) => {
const updateSecrets: BatchSecret[] = []; const updateSecrets: BatchSecret[] = [];
const deleteSecrets: Types.ObjectId[] = []; const deleteSecrets: Types.ObjectId[] = [];
const actions: IAction[] = []; const actions: IAction[] = [];
// get secret blind index salt // get secret blind index salt
const salt = await SecretService.getSecretBlindIndexSalt({ const salt = await SecretService.getSecretBlindIndexSalt({
workspaceId: new Types.ObjectId(workspaceId) workspaceId: new Types.ObjectId(workspaceId)
}); });
for await (const request of requests) { for await (const request of requests) {
const folderId = request.secret.folderId
// TODO: need to auth folder
const fullFolderPath = await getFolderPath(folderId)
let secretBlindIndex = ''; let secretBlindIndex = '';
switch (request.method) { switch (request.method) {
case 'POST': case 'POST':
@@ -72,19 +79,23 @@ export const batchSecrets = async (req: Request, res: Response) => {
user: request.secret.type === SECRET_PERSONAL ? req.user : undefined, user: request.secret.type === SECRET_PERSONAL ? req.user : undefined,
environment, environment,
workspace: new Types.ObjectId(workspaceId), workspace: new Types.ObjectId(workspaceId),
path: fullFolderPath,
folder: folderId,
secretBlindIndex secretBlindIndex
}); });
break; break;
case 'PATCH': case 'PATCH':
secretBlindIndex = await SecretService.generateSecretBlindIndexWithSalt({ secretBlindIndex = await SecretService.generateSecretBlindIndexWithSalt({
secretName: request.secret.secretName, secretName: request.secret.secretName,
salt salt,
}); });
updateSecrets.push({ updateSecrets.push({
...request.secret, ...request.secret,
_id: new Types.ObjectId(request.secret._id), _id: new Types.ObjectId(request.secret._id),
secretBlindIndex secretBlindIndex,
folder: folderId,
path: fullFolderPath,
}); });
break; break;
case 'DELETE': case 'DELETE':
@@ -437,9 +448,9 @@ export const createSecrets = async (req: Request, res: Response) => {
}); });
}) })
); );
const newlyCreatedSecrets: ISecret[] = (await Secret.insertMany(secretsToInsert)).map((insertedSecret) => insertedSecret.toObject()); const newlyCreatedSecrets: ISecret[] = (await Secret.insertMany(secretsToInsert)).map((insertedSecret) => insertedSecret.toObject());
setTimeout(async () => { setTimeout(async () => {
// trigger event - push secrets // trigger event - push secrets
await EventService.handleEvent({ await EventService.handleEvent({
@@ -578,9 +589,11 @@ export const getSecrets = async (req: Request, res: Response) => {
} }
*/ */
const { tagSlugs } = req.query; const { tagSlugs, secretsPath } = req.query;
const workspaceId = req.query.workspaceId as string; const workspaceId = req.query.workspaceId as string;
const environment = req.query.environment as string; const environment = req.query.environment as string;
const normalizedPath = normalizePath(secretsPath as string)
const folders = await getFoldersInDirectory(workspaceId as string, environment as string, normalizedPath)
// secrets to return // secrets to return
let secrets: ISecret[] = []; let secrets: ISecret[] = [];
@@ -613,6 +626,12 @@ export const getSecrets = async (req: Request, res: Response) => {
] ]
} }
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) { if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds }; secretQuery.tags = { $in: tagIds };
} }
@@ -638,6 +657,13 @@ export const getSecrets = async (req: Request, res: Response) => {
] ]
} }
// TODO: check if user can query for given path
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) { if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds }; secretQuery.tags = { $in: tagIds };
} }
@@ -655,6 +681,12 @@ export const getSecrets = async (req: Request, res: Response) => {
user: { $exists: false } // shared secrets only from workspace user: { $exists: false } // shared secrets only from workspace
} }
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) { if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds }; secretQuery.tags = { $in: tagIds };
} }
@@ -701,7 +733,8 @@ export const getSecrets = async (req: Request, res: Response) => {
} }
return res.status(200).send({ return res.status(200).send({
secrets secrets,
folders
}); });
} }
+4 -2
View File
@@ -44,7 +44,8 @@ import {
password as v1PasswordRouter, password as v1PasswordRouter,
stripe as v1StripeRouter, stripe as v1StripeRouter,
integration as v1IntegrationRouter, integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter integrationAuth as v1IntegrationAuthRouter,
secretsFolder as v1SecretsFolder
} from './routes/v1'; } from './routes/v1';
import { import {
signup as v2SignupRouter, signup as v2SignupRouter,
@@ -137,6 +138,7 @@ const main = async () => {
app.use('/api/v1/stripe', v1StripeRouter); app.use('/api/v1/stripe', v1StripeRouter);
app.use('/api/v1/integration', v1IntegrationRouter); app.use('/api/v1/integration', v1IntegrationRouter);
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter); app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
app.use('/api/v1/folder', v1SecretsFolder)
// v2 routes (improvements) // v2 routes (improvements)
app.use('/api/v2/signup', v2SignupRouter); app.use('/api/v2/signup', v2SignupRouter);
@@ -151,7 +153,7 @@ const main = async () => {
app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route
app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new
app.use('/api/v2/api-key', v2APIKeyDataRouter); app.use('/api/v2/api-key', v2APIKeyDataRouter);
// v3 routes (experimental) // v3 routes (experimental)
app.use('/api/v3/secrets', v3SecretsRouter); app.use('/api/v3/secrets', v3SecretsRouter);
app.use('/api/v3/workspaces', v3WorkspacesRouter); app.use('/api/v3/workspaces', v3WorkspacesRouter);
+15 -1
View File
@@ -3,6 +3,7 @@ import {
SECRET_SHARED, SECRET_SHARED,
SECRET_PERSONAL, SECRET_PERSONAL,
} from '../variables'; } from '../variables';
import { ROOT_FOLDER_PATH } from '../utils/folder';
export interface ISecret { export interface ISecret {
_id: Types.ObjectId; _id: Types.ObjectId;
@@ -25,6 +26,8 @@ export interface ISecret {
secretCommentTag?: string; secretCommentTag?: string;
secretCommentHash?: string; secretCommentHash?: string;
tags?: string[]; tags?: string[];
path?: string;
folder?: Types.ObjectId;
} }
const secretSchema = new Schema<ISecret>( const secretSchema = new Schema<ISecret>(
@@ -107,7 +110,18 @@ const secretSchema = new Schema<ISecret>(
secretCommentHash: { secretCommentHash: {
type: String, type: String,
required: false required: false
} },
// the full path to the secret in relation to folders
path: {
type: String,
required: false,
default: ROOT_FOLDER_PATH
},
folder: {
type: Schema.Types.ObjectId,
ref: 'Folder',
required: false,
},
}, },
{ {
timestamps: true timestamps: true
+3 -1
View File
@@ -15,6 +15,7 @@ import password from './password';
import stripe from './stripe'; import stripe from './stripe';
import integration from './integration'; import integration from './integration';
import integrationAuth from './integrationAuth'; import integrationAuth from './integrationAuth';
import secretsFolder from './secretsFolder'
export { export {
signup, signup,
@@ -33,5 +34,6 @@ export {
password, password,
stripe, stripe,
integration, integration,
integrationAuth integrationAuth,
secretsFolder
}; };
+40
View File
@@ -0,0 +1,40 @@
import express, { Request, Response } from 'express';
const router = express.Router();
import {
requireAuth,
requireWorkspaceAuth,
validateRequest
} from '../../middleware';
import { body, param } from 'express-validator';
import { createFolder, deleteFolder } from '../../controllers/v1/secretsFolderController';
import { ADMIN, MEMBER } from '../../variables';
router.post(
'/',
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: 'body'
}),
body('workspaceId').exists(),
body('environment').exists(),
body('folderName').exists(),
body('parentFolderId'),
validateRequest,
createFolder
);
router.delete(
'/:folderId',
requireAuth({
acceptedAuthModes: ['jwt']
}),
param('folderId').exists(),
validateRequest,
deleteFolder
);
export default router;