Finish preliminary /v2/secrets routes for batch/single CRUD secrets endpoints

This commit is contained in:
Tuan Dang
2023-01-09 01:03:40 +07:00
parent 7e534629ff
commit 35d23cf55c
14 changed files with 918 additions and 171 deletions
+3 -1
View File
@@ -1,10 +1,12 @@
import secret from './secret';
import secret from './secret'; // stop-supporting
import secrets from './secrets';
import workspace from './workspace';
import serviceTokenData from './serviceTokenData';
import apiKeyData from './apiKeyData';
export {
secret,
secrets,
workspace,
serviceTokenData,
apiKeyData
+31 -40
View File
@@ -1,18 +1,21 @@
import express, { Request, Response } from 'express';
import { requireAuth, requireWorkspaceAuth, validateRequest } from '../../middleware';
import express from 'express';
import {
requireAuth,
requireWorkspaceAuth,
requireSecretAuth,
validateRequest
} from '../../middleware';
import { body, param, query } from 'express-validator';
import { ADMIN, MEMBER } from '../../variables';
import { CreateSecretRequestBody, ModifySecretRequestBody } from '../../types/secret';
import { secretController } from '../../controllers/v2';
import { fetchAllSecrets, fetchSingleSecret } from '../../controllers/v2/secretController';
// note to devs: stop supporting
const router = express.Router();
/**
* Create many secrets for a given workspace and environmentName
*/
router.post(
'/batch-create/workspace/:workspaceId/environment/:environmentName',
'/batch-create/workspace/:workspaceId/environment/:environment',
requireAuth({
acceptedAuthModes: ['jwt']
}),
@@ -20,17 +23,15 @@ router.post(
acceptedRoles: [ADMIN, MEMBER]
}),
param('workspaceId').exists().isMongoId().trim(),
param('environmentName').exists().trim(),
param('environment').exists().trim(),
body('secrets').exists().isArray().custom((value) => value.every((item: CreateSecretRequestBody) => typeof item === 'object')),
body('channel'),
validateRequest,
secretController.batchCreateSecrets
secretController.createSecrets
);
/**
* Create single secret for a given workspace and environmentName
*/
router.post(
'/workspace/:workspaceId/environment/:environmentName',
'/workspace/:workspaceId/environment/:environment',
requireAuth({
acceptedAuthModes: ['jwt']
}),
@@ -38,15 +39,13 @@ router.post(
acceptedRoles: [ADMIN, MEMBER]
}),
param('workspaceId').exists().isMongoId().trim(),
param('environmentName').exists().trim(),
param('environment').exists().trim(),
body('secret').exists().isObject(),
body('channel'),
validateRequest,
secretController.createSingleSecret
secretController.createSecret
);
/**
* Get all secrets for a given environment and workspace id
*/
router.get(
'/workspace/:workspaceId',
param('workspaceId').exists().trim(),
@@ -57,25 +56,23 @@ router.get(
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
query('channel'),
validateRequest,
fetchAllSecrets
secretController.getSecrets
);
/**
* Get single secret by id
*/
router.get(
'/:secretId',
requireAuth({
acceptedAuthModes: ['jwt', 'serviceToken']
}),
requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
validateRequest,
fetchSingleSecret
secretController.getSecret
);
/**
* Batch delete secrets in a given workspace and environment name
*/
router.delete(
'/batch/workspace/:workspaceId/environment/:environmentName',
requireAuth({
@@ -88,26 +85,22 @@ router.delete(
acceptedRoles: [ADMIN, MEMBER]
}),
validateRequest,
secretController.batchDeleteSecrets
secretController.deleteSecrets
);
/**
* delete single secret by id
*/
router.delete(
'/:secretId',
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
param('secretId').isMongoId(),
validateRequest,
secretController.deleteSingleSecret
secretController.deleteSecret
);
/**
* Apply modifications to many existing secrets in a given workspace and environment
*/
router.patch(
'/batch-modify/workspace/:workspaceId/environment/:environmentName',
requireAuth({
@@ -120,12 +113,10 @@ router.patch(
acceptedRoles: [ADMIN, MEMBER]
}),
validateRequest,
secretController.batchModifySecrets
secretController.updateSecrets
);
/**
* Apply modifications to single existing secret in a given workspace and environment
*/
router.patch(
'/workspace/:workspaceId/environment/:environmentName',
requireAuth({
@@ -138,7 +129,7 @@ router.patch(
acceptedRoles: [ADMIN, MEMBER]
}),
validateRequest,
secretController.modifySingleSecrets
secretController.updateSecret
);
export default router;
+177
View File
@@ -0,0 +1,177 @@
import express from 'express';
const router = express.Router();
import {
requireAuth,
requireWorkspaceAuth,
requireSecretsAuth,
validateRequest
} from '../../middleware';
import { query, check, body } from 'express-validator';
import { secretsController } from '../../controllers/v2';
import {
ADMIN,
MEMBER,
SECRET_PERSONAL,
SECRET_SHARED
} from '../../variables';
router.post(
'/',
body('workspaceId').exists().isString().trim(),
body('environment').exists().isString().trim().isIn(['dev', 'staging', 'prod', 'test']),
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 ||
!secret.secretValueCiphertext ||
!secret.secretValueIV ||
!secret.secretValueTag
) {
throw new Error('secrets array must contain objects that conform to the Secret interface');
}
}
} 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 array must contain objects that conform to the Secret interface');
}
} else {
throw new Error('secrets must be an object or an array of objects')
}
return true;
}),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
location: 'body'
}),
secretsController.createSecrets
);
router.get(
'/',
query('workspaceId').exists().trim(),
query('environment').exists().trim().isIn(['dev', 'staging', 'prod', 'test']),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt', 'serviceToken']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
location: 'query'
}),
secretsController.getSecrets
);
router.patch(
'/',
body('workspaceId').exists().trim(),
body('environment').exists().trim().isIn(['dev', 'staging', 'prod', 'test']),
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 ||
!secret.secretKeyCiphertext ||
!secret.secretKeyIV ||
!secret.secretKeyTag ||
!secret.secretValueCiphertext ||
!secret.secretValueIV ||
!secret.secretValueTag
) {
throw new Error('secrets array must contain objects that conform to the Secret interface');
}
}
} else if (typeof value === 'object') {
// case: update 1 secret
if (
!value.id ||
!value.secretKeyCiphertext ||
!value.secretKeyIV ||
!value.secretKeyTag ||
!value.secretValueCiphertext ||
!value.secretValueIV ||
!value.secretValueTag
) {
throw new Error('secrets array must contain objects that conform to the Secret interface');
}
} else {
throw new Error('secrets must be an object or an array of objects')
}
return true;
}),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
location: 'body'
}),
requireSecretsAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
secretsController.updateSecrets
);
router.delete(
'/',
[
check('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')
}
throw new Error('secretIds must be a string or an array of strings');
})
.not()
.isEmpty()
],
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireSecretsAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
secretsController.deleteSecrets
);
export default router;