mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 10:28:22 +00:00
merge with own change
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from 'express';
|
||||||
import { requireAuth, validateRequest } from '../../middleware';
|
import { requireAuth, requireWorkspaceAuth, validateRequest } from '../../middleware';
|
||||||
import { ISecret, Secret } from '../../models';
|
import { ISecret, Secret } from '../../models';
|
||||||
import { decryptSymmetric } from '../../utils/crypto';
|
import { decryptSymmetric } from '../../utils/crypto';
|
||||||
import { getLogger } from '../../utils/logger';
|
import { getLogger } from '../../utils/logger';
|
||||||
import { body, param, query, check } from 'express-validator';
|
import { body, param, query, check } from 'express-validator';
|
||||||
import { BadRequestError } from '../../utils/errors';
|
import { BadRequestError, UnauthorizedRequestError } from '../../utils/errors';
|
||||||
|
import { ADMIN, MEMBER, COMPLETED, GRANTED } from '../../variables';
|
||||||
|
import { ModifySecretPayload } from '../../types/secret';
|
||||||
|
import { AnyBulkWriteOperation } from 'mongodb';
|
||||||
|
import to from 'await-to-js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,6 +18,10 @@ const router = express.Router();
|
|||||||
router.post(
|
router.post(
|
||||||
'/', requireAuth,
|
'/', requireAuth,
|
||||||
body('secret').exists().isObject(),
|
body('secret').exists().isObject(),
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { secret }: { secret: ISecret[] } = req.body;
|
const { secret }: { secret: ISecret[] } = req.body;
|
||||||
@@ -29,6 +38,10 @@ router.post(
|
|||||||
*/
|
*/
|
||||||
router.post(
|
router.post(
|
||||||
'/bulk-create', requireAuth,
|
'/bulk-create', requireAuth,
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
body('secrets').exists().isArray().custom((value) => value.every((item: ISecret) => typeof item === 'object')),
|
body('secrets').exists().isArray().custom((value) => value.every((item: ISecret) => typeof item === 'object')),
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@@ -46,6 +59,10 @@ router.post(
|
|||||||
*/
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
'/:secretId', requireAuth, param('secretId').exists().trim(),
|
'/:secretId', requireAuth, param('secretId').exists().trim(),
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
validateRequest, async (req: Request, res: Response) => {
|
validateRequest, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const secretFromDB = await Secret.findById(req.params.secretId)
|
const secretFromDB = await Secret.findById(req.params.secretId)
|
||||||
@@ -61,6 +78,10 @@ router.get(
|
|||||||
*/
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
'/:bulk', requireAuth, param('secretId').exists().trim(),
|
'/:bulk', requireAuth, param('secretId').exists().trim(),
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
validateRequest, async (req: Request, res: Response) => {
|
validateRequest, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const secretFromDB = await Secret.findById(req.params.secretId)
|
const secretFromDB = await Secret.findById(req.params.secretId)
|
||||||
@@ -77,6 +98,10 @@ router.get(
|
|||||||
router.delete(
|
router.delete(
|
||||||
'/:secretId',
|
'/:secretId',
|
||||||
requireAuth,
|
requireAuth,
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
param('secretId').exists().trim(),
|
param('secretId').exists().trim(),
|
||||||
validateRequest, async (req: Request, res: Response) => {
|
validateRequest, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@@ -96,6 +121,10 @@ router.delete(
|
|||||||
router.delete(
|
router.delete(
|
||||||
'/batch',
|
'/batch',
|
||||||
requireAuth,
|
requireAuth,
|
||||||
|
requireWorkspaceAuth({
|
||||||
|
acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
}),
|
||||||
body('secretIds').exists().isArray(),
|
body('secretIds').exists().isArray(),
|
||||||
validateRequest, async (req: Request, res: Response) => {
|
validateRequest, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@@ -111,25 +140,66 @@ router.delete(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply modifications to many existing secrets
|
* Apply modifications to many existing secrets in a given workspace and environment
|
||||||
|
* Note: although we do not check access for environments, we will in the future
|
||||||
*/
|
*/
|
||||||
router.patch(
|
router.patch(
|
||||||
'/bulk-update',
|
'/bulk-modify/:workspaceId/:environmentName',
|
||||||
requireAuth,
|
requireAuth,
|
||||||
body('secrets').exists().isArray().custom((value) => value.every((item: ISecret) => typeof item === 'object')),
|
body('secrets').exists().isArray().custom((value) => value.every((item: ISecret) => typeof item === 'object')),
|
||||||
|
param('workspaceId').exists().trim(),
|
||||||
|
param('environmentName').exists().trim(),
|
||||||
|
// requireWorkspaceAuth({
|
||||||
|
// acceptedRoles: [ADMIN, MEMBER],
|
||||||
|
// acceptedStatuses: [COMPLETED, GRANTED]
|
||||||
|
// }),
|
||||||
validateRequest, async (req: Request, res: Response) => {
|
validateRequest, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { secrets }: { secrets: ISecret[] } = req.body;
|
const { workspaceId, environmentName } = req.params
|
||||||
|
const secretsModificationsRequested: ModifySecretPayload[] = req.body.secrets;
|
||||||
|
|
||||||
const operations = secrets.map((secretToUpdate: ISecret) => ({
|
const secretsUserCanModify: ISecret[] = await Secret.find({ workspace: workspaceId, environment: environmentName })
|
||||||
updateOne: { filter: { _id: secretToUpdate._id }, update: secretToUpdate },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const bulkModificationInfo = await Secret.bulkWrite(operations);
|
const secretsUserCanModifyMapBySecretId: Map<string, ISecret> = new Map<string, ISecret>();
|
||||||
|
secretsUserCanModify.forEach(secret => secretsUserCanModifyMapBySecretId.set(secret._id.toString(), secret))
|
||||||
|
|
||||||
return res.status(200).json(bulkModificationInfo)
|
// Check if the entity has access to the secret ids it wants to modify
|
||||||
} catch (error) {
|
const updateOperationsToPerform: AnyBulkWriteOperation<ISecret>[] = []
|
||||||
throw BadRequestError({ message: `Unable to process the bulk update. Double check the ids of the secrets` })
|
secretsModificationsRequested.forEach(userModifiedSecret => {
|
||||||
|
const canModifyRequestedSecret = secretsUserCanModifyMapBySecretId.has(userModifiedSecret._id.toString())
|
||||||
|
if (canModifyRequestedSecret) {
|
||||||
|
const oldSecretInDB = secretsUserCanModifyMapBySecretId.get(userModifiedSecret._id.toString())
|
||||||
|
|
||||||
|
if (oldSecretInDB !== undefined) {
|
||||||
|
oldSecretInDB.secretKeyCiphertext = userModifiedSecret.secretKeyCiphertext
|
||||||
|
oldSecretInDB.secretKeyIV = userModifiedSecret.secretKeyIV
|
||||||
|
oldSecretInDB.secretKeyTag = userModifiedSecret.secretKeyTag
|
||||||
|
oldSecretInDB.secretKeyHash = userModifiedSecret.secretKeyHash
|
||||||
|
oldSecretInDB.secretValueCiphertext = userModifiedSecret.secretValueCiphertext
|
||||||
|
oldSecretInDB.secretValueIV = userModifiedSecret.secretValueIV
|
||||||
|
oldSecretInDB.secretValueTag = userModifiedSecret.secretValueTag
|
||||||
|
oldSecretInDB.secretValueHash = userModifiedSecret.secretValueHash
|
||||||
|
oldSecretInDB.secretCommentCiphertext = userModifiedSecret.secretCommentCiphertext
|
||||||
|
oldSecretInDB.secretCommentIV = userModifiedSecret.secretCommentIV
|
||||||
|
oldSecretInDB.secretCommentTag = userModifiedSecret.secretCommentTag
|
||||||
|
oldSecretInDB.secretCommentHash = userModifiedSecret.secretCommentHash
|
||||||
|
|
||||||
|
const updateOperation = { updateOne: { filter: { _id: oldSecretInDB._id, workspace: oldSecretInDB.workspace }, update: { $inc: { version: 1 }, $set: oldSecretInDB } } }
|
||||||
|
updateOperationsToPerform.push(updateOperation)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw UnauthorizedRequestError({ message: "You do not have permission to modify one or more of the requested secrets" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const bulkModificationInfo = await Secret.bulkWrite(updateOperationsToPerform);
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
bulkModificationInfo
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
throw BadRequestError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { Omit } from 'utility-types';
|
||||||
|
import { ISecret } from '../../models';
|
||||||
|
|
||||||
|
export type ModifySecretPayload = Omit<ISecret, "user" | "version" | "environment" | "workspace">;
|
||||||
Generated
+30
@@ -6,6 +6,10 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "infisical",
|
"name": "infisical",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"await-to-js": "^3.0.0",
|
||||||
|
"utility-types": "^3.10.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.29.0",
|
"eslint": "^8.29.0",
|
||||||
"husky": "^8.0.2"
|
"husky": "^8.0.2"
|
||||||
@@ -169,6 +173,14 @@
|
|||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/await-to-js": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -1092,6 +1104,14 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/utility-types": {
|
||||||
|
"version": "3.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
|
||||||
|
"integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
@@ -1248,6 +1268,11 @@
|
|||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"await-to-js": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -1910,6 +1935,11 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"utility-types": {
|
||||||
|
"version": "3.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
|
||||||
|
"integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg=="
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@@ -21,5 +21,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.29.0",
|
"eslint": "^8.29.0",
|
||||||
"husky": "^8.0.2"
|
"husky": "^8.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"await-to-js": "^3.0.0",
|
||||||
|
"utility-types": "^3.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user