mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 22:46:24 +00:00
feat(folders): added support for snapshot by env and folder
This commit is contained in:
@@ -1,50 +1,70 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
requireWorkspaceAuth,
|
||||
validateRequest
|
||||
} from '../../middleware';
|
||||
import { body, param } from 'express-validator';
|
||||
import { createFolder, deleteFolder, getFolderById } from '../../controllers/v1/secretsFolderController';
|
||||
import { ADMIN, MEMBER } from '../../variables';
|
||||
validateRequest,
|
||||
} from "../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
createFolder,
|
||||
deleteFolder,
|
||||
getFolders,
|
||||
updateFolderById,
|
||||
} from "../../controllers/v1/secretsFolderController";
|
||||
import { ADMIN, MEMBER } from "../../variables";
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ['jwt']
|
||||
acceptedAuthModes: ["jwt"],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'body'
|
||||
locationWorkspaceId: "body",
|
||||
}),
|
||||
body('workspaceId').exists(),
|
||||
body('environment').exists(),
|
||||
body('folderName').exists(),
|
||||
body('parentFolderId'),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
body("folderName").exists(),
|
||||
body("parentFolderId"),
|
||||
validateRequest,
|
||||
createFolder
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/:folderId',
|
||||
router.patch(
|
||||
"/:folderId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ['jwt']
|
||||
acceptedAuthModes: ["jwt"],
|
||||
}),
|
||||
param('folderId').exists(),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
param("folderId").not().isIn(["root"]).exists(),
|
||||
validateRequest,
|
||||
updateFolderById
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/:folderId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
}),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
param("folderId").not().isIn(["root"]).exists(),
|
||||
validateRequest,
|
||||
deleteFolder
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/:folderId',
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ['jwt']
|
||||
acceptedAuthModes: ["jwt"],
|
||||
}),
|
||||
param('folderId').exists(),
|
||||
query("workspaceId").exists().isString().trim(),
|
||||
query("environment").exists().isString().trim(),
|
||||
query("parentFolderId").optional().isString().trim(),
|
||||
validateRequest,
|
||||
getFolderById
|
||||
getFolders
|
||||
);
|
||||
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
+201
-172
@@ -2,204 +2,233 @@ import express from 'express';
|
||||
const router = express.Router();
|
||||
import { Types } from 'mongoose';
|
||||
import {
|
||||
requireAuth,
|
||||
requireWorkspaceAuth,
|
||||
requireSecretsAuth,
|
||||
validateRequest
|
||||
requireAuth,
|
||||
requireWorkspaceAuth,
|
||||
requireSecretsAuth,
|
||||
validateRequest,
|
||||
} from '../../middleware';
|
||||
import { validateClientForSecrets } from '../../validation';
|
||||
import { query, body } from 'express-validator';
|
||||
import { secretsController } from '../../controllers/v2';
|
||||
import {
|
||||
ADMIN,
|
||||
MEMBER,
|
||||
SECRET_PERSONAL,
|
||||
SECRET_SHARED,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY
|
||||
ADMIN,
|
||||
MEMBER,
|
||||
SECRET_PERSONAL,
|
||||
SECRET_SHARED,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY,
|
||||
} from '../../variables';
|
||||
import {
|
||||
BatchSecretRequest
|
||||
} from '../../types/secret';
|
||||
import { BatchSecretRequest } from '../../types/secret';
|
||||
|
||||
router.post(
|
||||
'/batch',
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'body'
|
||||
}),
|
||||
body('workspaceId').exists().isString().trim(),
|
||||
body('environment').exists().isString().trim(),
|
||||
body('requests')
|
||||
.exists()
|
||||
.custom(async (requests: BatchSecretRequest[], { req }) => {
|
||||
if (Array.isArray(requests)) {
|
||||
const secretIds = requests
|
||||
.map((request) => request.secret._id)
|
||||
.filter((secretId) => secretId !== undefined)
|
||||
'/batch',
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'body',
|
||||
}),
|
||||
body('workspaceId').exists().isString().trim(),
|
||||
body('folderId').default('root').isString().trim(),
|
||||
body('environment').exists().isString().trim(),
|
||||
body('requests')
|
||||
.exists()
|
||||
.custom(async (requests: BatchSecretRequest[], { req }) => {
|
||||
if (Array.isArray(requests)) {
|
||||
const secretIds = requests
|
||||
.map((request) => request.secret._id)
|
||||
.filter((secretId) => secretId !== undefined);
|
||||
|
||||
if (secretIds.length > 0) {
|
||||
req.secrets = await validateClientForSecrets({
|
||||
authData: req.authData,
|
||||
secretIds: secretIds.map((secretId: string) => new Types.ObjectId(secretId)),
|
||||
requiredPermissions: []
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
validateRequest,
|
||||
secretsController.batchSecrets
|
||||
if (secretIds.length > 0) {
|
||||
req.secrets = await validateClientForSecrets({
|
||||
authData: req.authData,
|
||||
secretIds: secretIds.map(
|
||||
(secretId: string) => new Types.ObjectId(secretId)
|
||||
),
|
||||
requiredPermissions: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
validateRequest,
|
||||
secretsController.batchSecrets
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
body('workspaceId').exists().isString().trim(),
|
||||
body('environment').exists().isString().trim(),
|
||||
body('secrets')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
if (Array.isArray(value)) {
|
||||
// case: create multiple secrets
|
||||
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
||||
for (const secret of value) {
|
||||
if (
|
||||
!secret.type ||
|
||||
!(secret.type === SECRET_PERSONAL || secret.type === SECRET_SHARED) ||
|
||||
!secret.secretKeyCiphertext ||
|
||||
!secret.secretKeyIV ||
|
||||
!secret.secretKeyTag ||
|
||||
(typeof secret.secretValueCiphertext !== 'string') ||
|
||||
!secret.secretValueIV ||
|
||||
!secret.secretValueTag
|
||||
) {
|
||||
throw new Error('secrets array must contain objects that have required secret properties');
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
// case: update 1 secret
|
||||
if (
|
||||
!value.type ||
|
||||
!(value.type === SECRET_PERSONAL || value.type === SECRET_SHARED) ||
|
||||
!value.secretKeyCiphertext ||
|
||||
!value.secretKeyIV ||
|
||||
!value.secretKeyTag ||
|
||||
!value.secretValueCiphertext ||
|
||||
!value.secretValueIV ||
|
||||
!value.secretValueTag
|
||||
) {
|
||||
throw new Error('secrets object is missing required secret properties');
|
||||
}
|
||||
} else {
|
||||
throw new Error('secrets must be an object or an array of objects')
|
||||
}
|
||||
'/',
|
||||
body('workspaceId').exists().isString().trim(),
|
||||
body('environment').exists().isString().trim(),
|
||||
body('folderId').default('root').isString().trim(),
|
||||
body('secrets')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
if (Array.isArray(value)) {
|
||||
// case: create multiple secrets
|
||||
if (value.length === 0)
|
||||
throw new Error('secrets cannot be an empty array');
|
||||
for (const secret of value) {
|
||||
if (
|
||||
!secret.type ||
|
||||
!(
|
||||
secret.type === SECRET_PERSONAL || secret.type === SECRET_SHARED
|
||||
) ||
|
||||
!secret.secretKeyCiphertext ||
|
||||
!secret.secretKeyIV ||
|
||||
!secret.secretKeyTag ||
|
||||
typeof secret.secretValueCiphertext !== 'string' ||
|
||||
!secret.secretValueIV ||
|
||||
!secret.secretValueTag
|
||||
) {
|
||||
throw new Error(
|
||||
'secrets array must contain objects that have required secret properties'
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
// case: update 1 secret
|
||||
if (
|
||||
!value.type ||
|
||||
!(value.type === SECRET_PERSONAL || value.type === SECRET_SHARED) ||
|
||||
!value.secretKeyCiphertext ||
|
||||
!value.secretKeyIV ||
|
||||
!value.secretKeyTag ||
|
||||
!value.secretValueCiphertext ||
|
||||
!value.secretValueIV ||
|
||||
!value.secretValueTag
|
||||
) {
|
||||
throw new Error(
|
||||
'secrets object is missing required secret properties'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('secrets must be an object or an array of objects');
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
return true;
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'body',
|
||||
locationEnvironment: 'body',
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||
}),
|
||||
secretsController.createSecrets
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'body',
|
||||
locationEnvironment: 'body',
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS],
|
||||
}),
|
||||
secretsController.createSecrets
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
query('workspaceId').exists().trim(),
|
||||
query('environment').exists().trim(),
|
||||
query('tagSlugs'),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_SERVICE_ACCOUNT]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'query',
|
||||
locationEnvironment: 'query',
|
||||
requiredPermissions: [PERMISSION_READ_SECRETS]
|
||||
}),
|
||||
secretsController.getSecrets
|
||||
'/',
|
||||
query('workspaceId').exists().trim(),
|
||||
query('environment').exists().trim(),
|
||||
query('tagSlugs'),
|
||||
query('folderId').default('root').isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: 'query',
|
||||
locationEnvironment: 'query',
|
||||
requiredPermissions: [PERMISSION_READ_SECRETS],
|
||||
}),
|
||||
secretsController.getSecrets
|
||||
);
|
||||
|
||||
router.patch(
|
||||
'/',
|
||||
body('secrets')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
if (Array.isArray(value)) {
|
||||
// case: update multiple secrets
|
||||
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
||||
for (const secret of value) {
|
||||
if (
|
||||
!secret.id
|
||||
) {
|
||||
throw new Error('Each secret must contain a ID property');
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
// case: update 1 secret
|
||||
if (
|
||||
!value.id
|
||||
) {
|
||||
throw new Error('secret must contain a ID property');
|
||||
}
|
||||
} else {
|
||||
throw new Error('secrets must be an object or an array of objects')
|
||||
}
|
||||
'/',
|
||||
body('secrets')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
if (Array.isArray(value)) {
|
||||
// case: update multiple secrets
|
||||
if (value.length === 0)
|
||||
throw new Error('secrets cannot be an empty array');
|
||||
for (const secret of value) {
|
||||
if (!secret.id) {
|
||||
throw new Error('Each secret must contain a ID property');
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
// case: update 1 secret
|
||||
if (!value.id) {
|
||||
throw new Error('secret must contain a ID property');
|
||||
}
|
||||
} else {
|
||||
throw new Error('secrets must be an object or an array of objects');
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
return true;
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||
}),
|
||||
secretsController.updateSecrets
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
],
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS],
|
||||
}),
|
||||
secretsController.updateSecrets
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/',
|
||||
body('secretIds')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
// case: delete 1 secret
|
||||
if (typeof value === 'string') return true;
|
||||
'/',
|
||||
body('secretIds')
|
||||
.exists()
|
||||
.custom((value) => {
|
||||
// case: delete 1 secret
|
||||
if (typeof value === 'string') return true;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// case: delete multiple secrets
|
||||
if (value.length === 0) throw new Error('secrets cannot be an empty array');
|
||||
return value.every((id: string) => typeof id === 'string')
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
// case: delete multiple secrets
|
||||
if (value.length === 0)
|
||||
throw new Error('secrets cannot be an empty array');
|
||||
return value.every((id: string) => typeof id === 'string');
|
||||
}
|
||||
|
||||
throw new Error('secretIds must be a string or an array of strings');
|
||||
})
|
||||
.not()
|
||||
.isEmpty(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||
}),
|
||||
secretsController.deleteSecrets
|
||||
throw new Error('secretIds must be a string or an array of strings');
|
||||
})
|
||||
.not()
|
||||
.isEmpty(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
],
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_WRITE_SECRETS],
|
||||
}),
|
||||
secretsController.deleteSecrets
|
||||
);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user