merge with own change

This commit is contained in:
Maidul Islam
2022-12-31 17:48:56 -05:00
parent 618dc10e45
commit 60445727e9
4 changed files with 120 additions and 12 deletions
+82 -12
View File
@@ -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()
} }
} }
); );
+4
View File
@@ -0,0 +1,4 @@
import { Omit } from 'utility-types';
import { ISecret } from '../../models';
export type ModifySecretPayload = Omit<ISecret, "user" | "version" | "environment" | "workspace">;
+30
View File
@@ -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",
+4
View File
@@ -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"
} }
} }