mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 22:28:15 +00:00
add folders to batch and get secrets api
This commit is contained in:
@@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user