mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 06:27:40 +00:00
Update modify secrets api v2 so that fields are optional
This commit is contained in:
@@ -2,8 +2,8 @@ import to from 'await-to-js';
|
|||||||
import { Types } from 'mongoose';
|
import { Types } from 'mongoose';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { ISecret, Secret } from '../../models';
|
import { ISecret, Secret } from '../../models';
|
||||||
import {
|
import {
|
||||||
SECRET_PERSONAL,
|
SECRET_PERSONAL,
|
||||||
SECRET_SHARED,
|
SECRET_SHARED,
|
||||||
ACTION_ADD_SECRETS,
|
ACTION_ADD_SECRETS,
|
||||||
ACTION_READ_SECRETS,
|
ACTION_READ_SECRETS,
|
||||||
@@ -23,9 +23,9 @@ import { BadRequestError } from '../../utils/errors';
|
|||||||
* @param res
|
* @param res
|
||||||
*/
|
*/
|
||||||
export const createSecrets = async (req: Request, res: Response) => {
|
export const createSecrets = async (req: Request, res: Response) => {
|
||||||
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
||||||
const { workspaceId, environment } = req.body;
|
const { workspaceId, environment } = req.body;
|
||||||
|
|
||||||
let toAdd;
|
let toAdd;
|
||||||
if (Array.isArray(req.body.secrets)) {
|
if (Array.isArray(req.body.secrets)) {
|
||||||
// case: create multiple secrets
|
// case: create multiple secrets
|
||||||
@@ -34,7 +34,7 @@ export const createSecrets = async (req: Request, res: Response) => {
|
|||||||
// case: create 1 secret
|
// case: create 1 secret
|
||||||
toAdd = [req.body.secrets];
|
toAdd = [req.body.secrets];
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSecrets = await Secret.insertMany(
|
const newSecrets = await Secret.insertMany(
|
||||||
toAdd.map(({
|
toAdd.map(({
|
||||||
type,
|
type,
|
||||||
@@ -66,7 +66,7 @@ export const createSecrets = async (req: Request, res: Response) => {
|
|||||||
secretValueTag
|
secretValueTag
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
// (EE) add secret versions for new secrets
|
// (EE) add secret versions for new secrets
|
||||||
EESecretService.addSecretVersions({
|
EESecretService.addSecretVersions({
|
||||||
secretVersions: newSecrets.map(({
|
secretVersions: newSecrets.map(({
|
||||||
@@ -160,7 +160,7 @@ export const createSecrets = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const getSecrets = async (req: Request, res: Response) => {
|
export const getSecrets = async (req: Request, res: Response) => {
|
||||||
const { workspaceId, environment } = req.query;
|
const { workspaceId, environment } = req.query;
|
||||||
|
|
||||||
let userId: Types.ObjectId | undefined = undefined // used for getting personal secrets for user
|
let userId: Types.ObjectId | undefined = undefined // used for getting personal secrets for user
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
userId = req.user._id;
|
userId = req.user._id;
|
||||||
@@ -169,13 +169,13 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
if (req.serviceTokenData) {
|
if (req.serviceTokenData) {
|
||||||
userId = req.serviceTokenData.user._id
|
userId = req.serviceTokenData.user._id
|
||||||
}
|
}
|
||||||
|
|
||||||
const [err, secrets] = await to(Secret.find(
|
const [err, secrets] = await to(Secret.find(
|
||||||
{
|
{
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
$or: [
|
$or: [
|
||||||
{ user: userId },
|
{ user: userId },
|
||||||
{ user: { $exists: false } }
|
{ user: { $exists: false } }
|
||||||
],
|
],
|
||||||
type: { $in: [SECRET_SHARED, SECRET_PERSONAL] }
|
type: { $in: [SECRET_SHARED, SECRET_PERSONAL] }
|
||||||
@@ -183,9 +183,9 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
).then())
|
).then())
|
||||||
|
|
||||||
if (err) throw ValidationError({ message: 'Failed to get secrets', stack: err.stack });
|
if (err) throw ValidationError({ message: 'Failed to get secrets', stack: err.stack });
|
||||||
|
|
||||||
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
||||||
|
|
||||||
const readAction = await EELogService.createActionSecret({
|
const readAction = await EELogService.createActionSecret({
|
||||||
name: ACTION_READ_SECRETS,
|
name: ACTION_READ_SECRETS,
|
||||||
userId: req.user._id.toString(),
|
userId: req.user._id.toString(),
|
||||||
@@ -214,7 +214,7 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
secrets
|
secrets
|
||||||
});
|
});
|
||||||
@@ -226,8 +226,8 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
* @param res
|
* @param res
|
||||||
*/
|
*/
|
||||||
export const updateSecrets = async (req: Request, res: Response) => {
|
export const updateSecrets = async (req: Request, res: Response) => {
|
||||||
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
||||||
|
|
||||||
// TODO: move type
|
// TODO: move type
|
||||||
interface PatchSecret {
|
interface PatchSecret {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -242,7 +242,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
secretCommentTag: string;
|
secretCommentTag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ops = req.body.secrets.map((secret: PatchSecret) => {
|
const updateOperationsToPerform = req.body.secrets.map((secret: PatchSecret) => {
|
||||||
const {
|
const {
|
||||||
secretKeyCiphertext,
|
secretKeyCiphertext,
|
||||||
secretKeyIV,
|
secretKeyIV,
|
||||||
@@ -254,6 +254,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
secretCommentIV,
|
secretCommentIV,
|
||||||
secretCommentTag
|
secretCommentTag
|
||||||
} = secret;
|
} = secret;
|
||||||
|
|
||||||
return ({
|
return ({
|
||||||
updateOne: {
|
updateOne: {
|
||||||
filter: { _id: new Types.ObjectId(secret.id) },
|
filter: { _id: new Types.ObjectId(secret.id) },
|
||||||
@@ -268,8 +269,8 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
secretValueIV,
|
secretValueIV,
|
||||||
secretValueTag,
|
secretValueTag,
|
||||||
...((
|
...((
|
||||||
secretCommentCiphertext &&
|
secretCommentCiphertext &&
|
||||||
secretCommentIV &&
|
secretCommentIV &&
|
||||||
secretCommentTag
|
secretCommentTag
|
||||||
) ? {
|
) ? {
|
||||||
secretCommentCiphertext,
|
secretCommentCiphertext,
|
||||||
@@ -280,15 +281,17 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await Secret.bulkWrite(ops);
|
|
||||||
|
await Secret.bulkWrite(updateOperationsToPerform);
|
||||||
const newSecretsObj: { [key: string]: PatchSecret } = {};
|
|
||||||
|
const secretModificationsBySecretId: { [key: string]: PatchSecret } = {};
|
||||||
req.body.secrets.forEach((secret: PatchSecret) => {
|
req.body.secrets.forEach((secret: PatchSecret) => {
|
||||||
newSecretsObj[secret.id] = secret;
|
secretModificationsBySecretId[secret.id] = secret;
|
||||||
});
|
});
|
||||||
|
|
||||||
await EESecretService.addSecretVersions({
|
const ListOfSecretsBeforeModifications = req.secrets
|
||||||
secretVersions: req.secrets.map((secret: ISecret) => {
|
const secretVersions = {
|
||||||
|
secretVersions: ListOfSecretsBeforeModifications.map((secret: ISecret) => {
|
||||||
const {
|
const {
|
||||||
secretKeyCiphertext,
|
secretKeyCiphertext,
|
||||||
secretKeyIV,
|
secretKeyIV,
|
||||||
@@ -298,37 +301,29 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
secretValueTag,
|
secretValueTag,
|
||||||
secretCommentCiphertext,
|
secretCommentCiphertext,
|
||||||
secretCommentIV,
|
secretCommentIV,
|
||||||
secretCommentTag
|
secretCommentTag,
|
||||||
} = newSecretsObj[secret._id.toString()]
|
} = secretModificationsBySecretId[secret._id.toString()]
|
||||||
|
|
||||||
return ({
|
return ({
|
||||||
secret: secret._id,
|
secret: secret._id,
|
||||||
version: secret.version + 1,
|
version: secret.version + 1,
|
||||||
workspace: secret.workspace,
|
workspace: secret.workspace,
|
||||||
type: secret.type,
|
type: secret.type,
|
||||||
environment: secret.environment,
|
environment: secret.environment,
|
||||||
isDeleted: false,
|
secretKeyCiphertext: secretKeyCiphertext ? secretKeyCiphertext : secret.secretKeyCiphertext,
|
||||||
secretKeyCiphertext,
|
secretKeyIV: secretKeyIV ? secretKeyIV : secret.secretKeyIV,
|
||||||
secretKeyIV,
|
secretKeyTag: secretKeyTag ? secretKeyTag : secret.secretKeyTag,
|
||||||
secretKeyTag,
|
secretValueCiphertext: secretValueCiphertext ? secretValueCiphertext : secret.secretValueCiphertext,
|
||||||
secretValueCiphertext,
|
secretValueIV: secretValueIV ? secretValueIV : secret.secretValueIV,
|
||||||
secretValueIV,
|
secretValueTag: secretValueTag ? secretValueTag : secret.secretValueTag,
|
||||||
secretValueTag,
|
secretCommentCiphertext: secretCommentCiphertext ? secretCommentCiphertext : secret.secretCommentCiphertext,
|
||||||
...((
|
secretCommentIV: secretCommentIV ? secretCommentIV : secret.secretCommentIV,
|
||||||
secretCommentCiphertext &&
|
secretCommentTag: secretCommentTag ? secretCommentTag : secret.secretCommentTag,
|
||||||
secretCommentIV &&
|
|
||||||
secretCommentTag
|
|
||||||
) ? {
|
|
||||||
secretCommentCiphertext,
|
|
||||||
secretCommentIV,
|
|
||||||
secretCommentTag
|
|
||||||
} : {
|
|
||||||
secretCommentCiphertext: '',
|
|
||||||
secretCommentIV: '',
|
|
||||||
secretCommentTag: ''
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
}
|
||||||
|
|
||||||
|
await EESecretService.addSecretVersions(secretVersions);
|
||||||
|
|
||||||
|
|
||||||
// group secrets into workspaces so updated secrets can
|
// group secrets into workspaces so updated secrets can
|
||||||
@@ -355,7 +350,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
userId: req.user._id.toString(),
|
userId: req.user._id.toString(),
|
||||||
workspaceId: key,
|
workspaceId: key,
|
||||||
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
||||||
});
|
});
|
||||||
|
|
||||||
// (EE) create (audit) log
|
// (EE) create (audit) log
|
||||||
updateAction && await EELogService.createLog({
|
updateAction && await EELogService.createLog({
|
||||||
@@ -367,9 +362,9 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// (EE) take a secret snapshot
|
// (EE) take a secret snapshot
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId: key
|
workspaceId: key
|
||||||
})
|
})
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
@@ -385,7 +380,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
secrets: await Secret.find({
|
secrets: await Secret.find({
|
||||||
_id: {
|
_id: {
|
||||||
@@ -401,15 +396,15 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
* @param res
|
* @param res
|
||||||
*/
|
*/
|
||||||
export const deleteSecrets = async (req: Request, res: Response) => {
|
export const deleteSecrets = async (req: Request, res: Response) => {
|
||||||
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
|
||||||
const toDelete = req.secrets.map((s: any) => s._id);
|
const toDelete = req.secrets.map((s: any) => s._id);
|
||||||
|
|
||||||
await Secret.deleteMany({
|
await Secret.deleteMany({
|
||||||
_id: {
|
_id: {
|
||||||
$in: toDelete
|
$in: toDelete
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await EESecretService.markDeletedSecretVersions({
|
await EESecretService.markDeletedSecretVersions({
|
||||||
secretIds: toDelete
|
secretIds: toDelete
|
||||||
});
|
});
|
||||||
@@ -437,7 +432,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
|||||||
userId: req.user._id.toString(),
|
userId: req.user._id.toString(),
|
||||||
workspaceId: key,
|
workspaceId: key,
|
||||||
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
||||||
});
|
});
|
||||||
|
|
||||||
// (EE) create (audit) log
|
// (EE) create (audit) log
|
||||||
deleteAction && await EELogService.createLog({
|
deleteAction && await EELogService.createLog({
|
||||||
@@ -449,9 +444,9 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// (EE) take a secret snapshot
|
// (EE) take a secret snapshot
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId: key
|
workspaceId: key
|
||||||
})
|
})
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
@@ -467,7 +462,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
secrets: req.secrets
|
secrets: req.secrets
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Types } from 'mongoose';
|
import { Types } from 'mongoose';
|
||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import {
|
import {
|
||||||
Secret,
|
Secret,
|
||||||
ISecret
|
ISecret
|
||||||
} from '../../models';
|
} from '../../models';
|
||||||
import {
|
import {
|
||||||
SecretSnapshot,
|
SecretSnapshot,
|
||||||
SecretVersion,
|
SecretVersion,
|
||||||
ISecretVersion
|
ISecretVersion
|
||||||
} from '../models';
|
} from '../models';
|
||||||
@@ -18,24 +18,24 @@ import {
|
|||||||
* @param {String} obj.workspaceId
|
* @param {String} obj.workspaceId
|
||||||
* @returns {SecretSnapshot} secretSnapshot - new secret snapshot
|
* @returns {SecretSnapshot} secretSnapshot - new secret snapshot
|
||||||
*/
|
*/
|
||||||
const takeSecretSnapshotHelper = async ({
|
const takeSecretSnapshotHelper = async ({
|
||||||
workspaceId
|
workspaceId
|
||||||
}: {
|
}: {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
let secretSnapshot;
|
let secretSnapshot;
|
||||||
try {
|
try {
|
||||||
const secretIds = (await Secret.find({
|
const secretIds = (await Secret.find({
|
||||||
workspace: workspaceId
|
workspace: workspaceId
|
||||||
}, '_id')).map((s) => s._id);
|
}, '_id')).map((s) => s._id);
|
||||||
|
|
||||||
const latestSecretVersions = (await SecretVersion.aggregate([
|
const latestSecretVersions = (await SecretVersion.aggregate([
|
||||||
{
|
{
|
||||||
$match: {
|
$match: {
|
||||||
secret: {
|
secret: {
|
||||||
$in: secretIds
|
$in: secretIds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,14 +48,14 @@ import {
|
|||||||
{
|
{
|
||||||
$sort: { version: -1 }
|
$sort: { version: -1 }
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
.exec())
|
.exec())
|
||||||
.map((s) => s.versionId);
|
.map((s) => s.versionId);
|
||||||
|
|
||||||
const latestSecretSnapshot = await SecretSnapshot.findOne({
|
const latestSecretSnapshot = await SecretSnapshot.findOne({
|
||||||
workspace: workspaceId
|
workspace: workspaceId
|
||||||
}).sort({ version: -1 });
|
}).sort({ version: -1 });
|
||||||
|
|
||||||
secretSnapshot = await new SecretSnapshot({
|
secretSnapshot = await new SecretSnapshot({
|
||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
version: latestSecretSnapshot ? latestSecretSnapshot.version + 1 : 1,
|
version: latestSecretSnapshot ? latestSecretSnapshot.version + 1 : 1,
|
||||||
@@ -66,7 +66,7 @@ import {
|
|||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
throw new Error('Failed to take a secret snapshot');
|
throw new Error('Failed to take a secret snapshot');
|
||||||
}
|
}
|
||||||
|
|
||||||
return secretSnapshot;
|
return secretSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,9 +87,9 @@ const addSecretVersionsHelper = async ({
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
Sentry.setUser(null);
|
Sentry.setUser(null);
|
||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
throw new Error('Failed to add secret versions');
|
throw new Error(`Failed to add secret versions [err=${err}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newSecretVersions;
|
return newSecretVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,39 +120,39 @@ const markDeletedSecretVersionsHelper = async ({
|
|||||||
const initSecretVersioningHelper = async () => {
|
const initSecretVersioningHelper = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await Secret.updateMany(
|
await Secret.updateMany(
|
||||||
{ version: { $exists: false } },
|
{ version: { $exists: false } },
|
||||||
{ $set: { version: 1 } }
|
{ $set: { version: 1 } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const unversionedSecrets: ISecret[] = await Secret.aggregate([
|
const unversionedSecrets: ISecret[] = await Secret.aggregate([
|
||||||
{
|
{
|
||||||
$lookup: {
|
$lookup: {
|
||||||
from: 'secretversions',
|
from: 'secretversions',
|
||||||
localField: '_id',
|
localField: '_id',
|
||||||
foreignField: 'secret',
|
foreignField: 'secret',
|
||||||
as: 'versions',
|
as: 'versions',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$match: {
|
$match: {
|
||||||
versions: { $size: 0 },
|
versions: { $size: 0 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (unversionedSecrets.length > 0) {
|
if (unversionedSecrets.length > 0) {
|
||||||
await addSecretVersionsHelper({
|
await addSecretVersionsHelper({
|
||||||
secretVersions: unversionedSecrets.map((s, idx) => ({
|
secretVersions: unversionedSecrets.map((s, idx) => ({
|
||||||
...s,
|
...s,
|
||||||
secret: s._id,
|
secret: s._id,
|
||||||
version: s.version ? s.version : 1,
|
version: s.version ? s.version : 1,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
workspace: s.workspace,
|
workspace: s.workspace,
|
||||||
environment: s.environment
|
environment: s.environment
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Sentry.setUser(null);
|
Sentry.setUser(null);
|
||||||
@@ -162,7 +162,7 @@ const initSecretVersioningHelper = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
takeSecretSnapshotHelper,
|
takeSecretSnapshotHelper,
|
||||||
addSecretVersionsHelper,
|
addSecretVersionsHelper,
|
||||||
markDeletedSecretVersionsHelper,
|
markDeletedSecretVersionsHelper,
|
||||||
initSecretVersioningHelper
|
initSecretVersioningHelper
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import {
|
|||||||
|
|
||||||
export interface ISecretVersion {
|
export interface ISecretVersion {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
secret: Types.ObjectId;
|
secret: Types.ObjectId;
|
||||||
version: number;
|
version: number;
|
||||||
workspace: Types.ObjectId; // new
|
workspace: Types.ObjectId; // new
|
||||||
type: string; // new
|
type: string; // new
|
||||||
user: Types.ObjectId; // new
|
user: Types.ObjectId; // new
|
||||||
environment: string; // new
|
environment: string; // new
|
||||||
isDeleted: boolean;
|
isDeleted: boolean;
|
||||||
secretKeyCiphertext: string;
|
secretKeyCiphertext: string;
|
||||||
secretKeyIV: string;
|
secretKeyIV: string;
|
||||||
secretKeyTag: string;
|
secretKeyTag: string;
|
||||||
secretKeyHash: string;
|
secretKeyHash: string;
|
||||||
@@ -28,17 +28,17 @@ export interface ISecretVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const secretVersionSchema = new Schema<ISecretVersion>(
|
const secretVersionSchema = new Schema<ISecretVersion>(
|
||||||
{
|
{
|
||||||
secret: { // could be deleted
|
secret: { // could be deleted
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'Secret',
|
ref: 'Secret',
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
version: {
|
version: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1,
|
default: 1,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
workspace: {
|
workspace: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'Workspace',
|
ref: 'Workspace',
|
||||||
@@ -59,12 +59,12 @@ const secretVersionSchema = new Schema<ISecretVersion>(
|
|||||||
enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD],
|
enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD],
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
isDeleted: { // consider removing field
|
isDeleted: { // consider removing field
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
secretKeyCiphertext: {
|
secretKeyCiphertext: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
@@ -94,10 +94,10 @@ const secretVersionSchema = new Schema<ISecretVersion>(
|
|||||||
secretValueHash: {
|
secretValueHash: {
|
||||||
type: String
|
type: String
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timestamps: true
|
timestamps: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const SecretVersion = model<ISecretVersion>('SecretVersion', secretVersionSchema);
|
const SecretVersion = model<ISecretVersion>('SecretVersion', secretVersionSchema);
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
} from '../../middleware';
|
} from '../../middleware';
|
||||||
import { query, check, body } from 'express-validator';
|
import { query, check, body } from 'express-validator';
|
||||||
import { secretsController } from '../../controllers/v2';
|
import { secretsController } from '../../controllers/v2';
|
||||||
import {
|
import {
|
||||||
ADMIN,
|
ADMIN,
|
||||||
MEMBER,
|
MEMBER,
|
||||||
SECRET_PERSONAL,
|
SECRET_PERSONAL,
|
||||||
SECRET_SHARED
|
SECRET_SHARED
|
||||||
@@ -27,7 +27,7 @@ router.post(
|
|||||||
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
||||||
for (const secret of value) {
|
for (const secret of value) {
|
||||||
if (
|
if (
|
||||||
!secret.type ||
|
!secret.type ||
|
||||||
!(secret.type === SECRET_PERSONAL || secret.type === SECRET_SHARED) ||
|
!(secret.type === SECRET_PERSONAL || secret.type === SECRET_SHARED) ||
|
||||||
!secret.secretKeyCiphertext ||
|
!secret.secretKeyCiphertext ||
|
||||||
!secret.secretKeyIV ||
|
!secret.secretKeyIV ||
|
||||||
@@ -42,7 +42,7 @@ router.post(
|
|||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
// case: update 1 secret
|
// case: update 1 secret
|
||||||
if (
|
if (
|
||||||
!value.type ||
|
!value.type ||
|
||||||
!(value.type === SECRET_PERSONAL || value.type === SECRET_SHARED) ||
|
!(value.type === SECRET_PERSONAL || value.type === SECRET_SHARED) ||
|
||||||
!value.secretKeyCiphertext ||
|
!value.secretKeyCiphertext ||
|
||||||
!value.secretKeyIV ||
|
!value.secretKeyIV ||
|
||||||
@@ -52,13 +52,13 @@ router.post(
|
|||||||
!value.secretValueTag
|
!value.secretValueTag
|
||||||
) {
|
) {
|
||||||
throw new Error('secrets object is missing required secret properties');
|
throw new Error('secrets object is missing required secret properties');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('secrets must be an object or an array of objects')
|
throw new Error('secrets must be an object or an array of objects')
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
validateRequest,
|
validateRequest,
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: ['jwt']
|
acceptedAuthModes: ['jwt']
|
||||||
@@ -95,36 +95,24 @@ router.patch(
|
|||||||
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
if (value.length === 0) throw new Error('secrets cannot be an empty array')
|
||||||
for (const secret of value) {
|
for (const secret of value) {
|
||||||
if (
|
if (
|
||||||
!secret.id ||
|
!secret.id
|
||||||
!secret.secretKeyCiphertext ||
|
|
||||||
!secret.secretKeyIV ||
|
|
||||||
!secret.secretKeyTag ||
|
|
||||||
!secret.secretValueCiphertext ||
|
|
||||||
!secret.secretValueIV ||
|
|
||||||
!secret.secretValueTag
|
|
||||||
) {
|
) {
|
||||||
throw new Error('secrets array must contain objects that have required secret properties');
|
throw new Error('Each secret must contain a ID property');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
// case: update 1 secret
|
// case: update 1 secret
|
||||||
if (
|
if (
|
||||||
!value.id ||
|
!value.id
|
||||||
!value.secretKeyCiphertext ||
|
|
||||||
!value.secretKeyIV ||
|
|
||||||
!value.secretKeyTag ||
|
|
||||||
!value.secretValueCiphertext ||
|
|
||||||
!value.secretValueIV ||
|
|
||||||
!value.secretValueTag
|
|
||||||
) {
|
) {
|
||||||
throw new Error('secrets object is missing required secret properties');
|
throw new Error('secret must contain a ID property');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('secrets must be an object or an array of objects')
|
throw new Error('secrets must be an object or an array of objects')
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
validateRequest,
|
validateRequest,
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: ['jwt']
|
acceptedAuthModes: ['jwt']
|
||||||
@@ -142,13 +130,13 @@ router.delete(
|
|||||||
.custom((value) => {
|
.custom((value) => {
|
||||||
// case: delete 1 secret
|
// case: delete 1 secret
|
||||||
if (typeof value === 'string') return true;
|
if (typeof value === 'string') return true;
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
// case: delete multiple secrets
|
// case: delete multiple secrets
|
||||||
if (value.length === 0) throw new Error('secrets cannot be an empty array');
|
if (value.length === 0) throw new Error('secrets cannot be an empty array');
|
||||||
return value.every((id: string) => typeof id === 'string')
|
return value.every((id: string) => typeof id === 'string')
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('secretIds must be a string or an array of strings');
|
throw new Error('secretIds must be a string or an array of strings');
|
||||||
})
|
})
|
||||||
.not()
|
.not()
|
||||||
|
|||||||
Reference in New Issue
Block a user